<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="generator" content="VuePress 2.0.0-beta.48" />
    <meta name="theme" content="VuePress Theme Hope" />
    <meta property="og:url" content="https://vuepress-theme-hope-v2-demo.mrhope.site/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html"><meta property="og:site_name" content="主题演示"><meta property="og:title" content="主流框架"><meta property="og:type" content="article"><meta property="og:locale" content="zh-CN"><meta property="og:locale:alternate" content="en-US"><meta property="article:tag" content="主流框架"><title>主流框架 | 主题演示</title><meta name="description" content="vuepress-theme-hope 的演示">
    <style>
      :root {
        --bg-color: #fff;
      }

      html[data-theme="dark"] {
        --bg-color: #1d2025;
      }

      html,
      body {
        background-color: var(--bg-color);
      }
    </style>
    <script>
      const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
      const systemDarkMode =
        window.matchMedia &&
        window.matchMedia("(prefers-color-scheme: dark)").matches;

      if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
        document.querySelector("html").setAttribute("data-theme", "dark");
      }
    </script>
    <link rel="stylesheet" href="/assets/style.dbbe025d.css">
    <link rel="modulepreload" href="/assets/app.e732cc94.js"><link rel="modulepreload" href="/assets/主流框架.html.48ca457c.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper.21dcd24c.js"><link rel="modulepreload" href="/assets/主流框架.html.f21f66df.js"><link rel="prefetch" href="/assets/home.html.d675c4b6.js"><link rel="prefetch" href="/assets/intro.html.684ef626.js"><link rel="prefetch" href="/assets/index.html.e8ffec66.js"><link rel="prefetch" href="/assets/slide.html.050a6f1e.js"><link rel="prefetch" href="/assets/disable.html.b507ecac.js"><link rel="prefetch" href="/assets/encrypt.html.762116d5.js"><link rel="prefetch" href="/assets/markdown.html.5acf7a9a.js"><link rel="prefetch" href="/assets/page.html.141b0147.js"><link rel="prefetch" href="/assets/index.html.75bf4c69.js"><link rel="prefetch" href="/assets/article10.html.f5ea4d77.js"><link rel="prefetch" href="/assets/article11.html.6339c214.js"><link rel="prefetch" href="/assets/article12.html.5ac86a8f.js"><link rel="prefetch" href="/assets/article9.html.666c37a0.js"><link rel="prefetch" href="/assets/home.html.6e361c52.js"><link rel="prefetch" href="/assets/index.html.2d9b62a7.js"><link rel="prefetch" href="/assets/slide.html.6b655fa0.js"><link rel="prefetch" href="/assets/article1.html.f835efef.js"><link rel="prefetch" href="/assets/article2.html.e4775195.js"><link rel="prefetch" href="/assets/article3.html.bfdf934f.js"><link rel="prefetch" href="/assets/article4.html.69bccee4.js"><link rel="prefetch" href="/assets/article5.html.c7ac5439.js"><link rel="prefetch" href="/assets/article6.html.880c0652.js"><link rel="prefetch" href="/assets/article7.html.2cae84db.js"><link rel="prefetch" href="/assets/article8.html.6c46837c.js"><link rel="prefetch" href="/assets/disable.html.f629efab.js"><link rel="prefetch" href="/assets/encrypt.html.58d61689.js"><link rel="prefetch" href="/assets/markdown.html.779c42bf.js"><link rel="prefetch" href="/assets/page.html.125d74f5.js"><link rel="prefetch" href="/assets/index.html.3db704fb.js"><link rel="prefetch" href="/assets/article10.html.b5d65d2d.js"><link rel="prefetch" href="/assets/article11.html.b2cf93ee.js"><link rel="prefetch" href="/assets/article12.html.94e1cf22.js"><link rel="prefetch" href="/assets/article9.html.90cf2a62.js"><link rel="prefetch" href="/assets/Docker.html.de1063e8.js"><link rel="prefetch" href="/assets/Java基础.html.6c0b0f5c.js"><link rel="prefetch" href="/assets/Java容器.html.77448ff5.js"><link rel="prefetch" href="/assets/JUC.html.76307785.js"><link rel="prefetch" href="/assets/JVM.html.0bb340ff.js"><link rel="prefetch" href="/assets/Linux.html.90ea1c3b.js"><link rel="prefetch" href="/assets/MySQL.html.73ae62bf.js"><link rel="prefetch" href="/assets/NIO与Netty.html.a73529b1.js"><link rel="prefetch" href="/assets/index.html.2a38d188.js"><link rel="prefetch" href="/assets/Redis.html.78427b11.js"><link rel="prefetch" href="/assets/分布式与高性能高可用.html.38ab4746.js"><link rel="prefetch" href="/assets/操作系统.html.76b600e3.js"><link rel="prefetch" href="/assets/智力题.html.ec368cec.js"><link rel="prefetch" href="/assets/系统设计.html.fb8f2074.js"><link rel="prefetch" href="/assets/计算机网络.html.1a7f7d0e.js"><link rel="prefetch" href="/assets/设计模式.html.cd48ccf5.js"><link rel="prefetch" href="/assets/article1.html.ca54de60.js"><link rel="prefetch" href="/assets/article2.html.a99d479f.js"><link rel="prefetch" href="/assets/article3.html.5a2797ee.js"><link rel="prefetch" href="/assets/article4.html.3ac5a509.js"><link rel="prefetch" href="/assets/article5.html.c09d20ba.js"><link rel="prefetch" href="/assets/article6.html.c9e59f52.js"><link rel="prefetch" href="/assets/article7.html.948e77cc.js"><link rel="prefetch" href="/assets/article8.html.28c3977f.js"><link rel="prefetch" href="/assets/404.html.8a909211.js"><link rel="prefetch" href="/assets/index.html.690b188a.js"><link rel="prefetch" href="/assets/index.html.6085d793.js"><link rel="prefetch" href="/assets/index.html.932078ca.js"><link rel="prefetch" href="/assets/index.html.bb629f30.js"><link rel="prefetch" href="/assets/index.html.92b2d70c.js"><link rel="prefetch" href="/assets/index.html.82840baf.js"><link rel="prefetch" href="/assets/index.html.85406aa8.js"><link rel="prefetch" href="/assets/index.html.7b9124b8.js"><link rel="prefetch" href="/assets/index.html.e1e2a548.js"><link rel="prefetch" href="/assets/index.html.a9a69593.js"><link rel="prefetch" href="/assets/index.html.5b51b72b.js"><link rel="prefetch" href="/assets/index.html.ec7f0295.js"><link rel="prefetch" href="/assets/index.html.e14e2286.js"><link rel="prefetch" href="/assets/index.html.e89216be.js"><link rel="prefetch" href="/assets/index.html.c0adb933.js"><link rel="prefetch" href="/assets/index.html.a45798a3.js"><link rel="prefetch" href="/assets/index.html.e99c516b.js"><link rel="prefetch" href="/assets/index.html.f6be7fb4.js"><link rel="prefetch" href="/assets/index.html.6812b391.js"><link rel="prefetch" href="/assets/index.html.4bae905e.js"><link rel="prefetch" href="/assets/index.html.0599248b.js"><link rel="prefetch" href="/assets/index.html.963b2596.js"><link rel="prefetch" href="/assets/index.html.bbd9778f.js"><link rel="prefetch" href="/assets/index.html.c6a7a8d4.js"><link rel="prefetch" href="/assets/index.html.13391f8f.js"><link rel="prefetch" href="/assets/index.html.4b0a0f3f.js"><link rel="prefetch" href="/assets/index.html.bbd06d0d.js"><link rel="prefetch" href="/assets/index.html.9a4d8710.js"><link rel="prefetch" href="/assets/index.html.dfdff039.js"><link rel="prefetch" href="/assets/index.html.cd21ad11.js"><link rel="prefetch" href="/assets/index.html.72b3c545.js"><link rel="prefetch" href="/assets/index.html.0262e65d.js"><link rel="prefetch" href="/assets/index.html.8905ca40.js"><link rel="prefetch" href="/assets/index.html.98e54f53.js"><link rel="prefetch" href="/assets/index.html.707c5120.js"><link rel="prefetch" href="/assets/index.html.daf3ede2.js"><link rel="prefetch" href="/assets/index.html.ae769b93.js"><link rel="prefetch" href="/assets/index.html.59a75e1b.js"><link rel="prefetch" href="/assets/index.html.efb1d101.js"><link rel="prefetch" href="/assets/index.html.898df6f8.js"><link rel="prefetch" href="/assets/index.html.6339ac7f.js"><link rel="prefetch" href="/assets/index.html.0ffdd311.js"><link rel="prefetch" href="/assets/index.html.454f52cf.js"><link rel="prefetch" href="/assets/index.html.d8a5ddde.js"><link rel="prefetch" href="/assets/index.html.3be06723.js"><link rel="prefetch" href="/assets/index.html.1d180388.js"><link rel="prefetch" href="/assets/index.html.337241b0.js"><link rel="prefetch" href="/assets/index.html.0be3cd3f.js"><link rel="prefetch" href="/assets/index.html.8e5505d4.js"><link rel="prefetch" href="/assets/index.html.ffdd1452.js"><link rel="prefetch" href="/assets/index.html.d3825f4c.js"><link rel="prefetch" href="/assets/home.html.ccae7996.js"><link rel="prefetch" href="/assets/intro.html.fd34d8e1.js"><link rel="prefetch" href="/assets/index.html.ba786069.js"><link rel="prefetch" href="/assets/slide.html.0df38877.js"><link rel="prefetch" href="/assets/disable.html.6465acbf.js"><link rel="prefetch" href="/assets/encrypt.html.f697c2c7.js"><link rel="prefetch" href="/assets/markdown.html.f534aa4c.js"><link rel="prefetch" href="/assets/page.html.d91d46f6.js"><link rel="prefetch" href="/assets/index.html.b66745bd.js"><link rel="prefetch" href="/assets/article10.html.a245f19a.js"><link rel="prefetch" href="/assets/article11.html.c7128e02.js"><link rel="prefetch" href="/assets/article12.html.abd25c27.js"><link rel="prefetch" href="/assets/article9.html.7bba6b9f.js"><link rel="prefetch" href="/assets/home.html.eb29b64c.js"><link rel="prefetch" href="/assets/index.html.a51898c1.js"><link rel="prefetch" href="/assets/slide.html.4db0d16b.js"><link rel="prefetch" href="/assets/article1.html.8aeaf420.js"><link rel="prefetch" href="/assets/article2.html.1b3af75b.js"><link rel="prefetch" href="/assets/article3.html.83bc62c6.js"><link rel="prefetch" href="/assets/article4.html.9c3e20ef.js"><link rel="prefetch" href="/assets/article5.html.a86dfd69.js"><link rel="prefetch" href="/assets/article6.html.1005b310.js"><link rel="prefetch" href="/assets/article7.html.e62a511b.js"><link rel="prefetch" href="/assets/article8.html.5d7e1f67.js"><link rel="prefetch" href="/assets/disable.html.9d48f34e.js"><link rel="prefetch" href="/assets/encrypt.html.69059b41.js"><link rel="prefetch" href="/assets/markdown.html.f8f89db4.js"><link rel="prefetch" href="/assets/page.html.f139635c.js"><link rel="prefetch" href="/assets/index.html.126e92a0.js"><link rel="prefetch" href="/assets/article10.html.f00bfbec.js"><link rel="prefetch" href="/assets/article11.html.4e4aea0e.js"><link rel="prefetch" href="/assets/article12.html.ed056ef8.js"><link rel="prefetch" href="/assets/article9.html.c3cb96a4.js"><link rel="prefetch" href="/assets/Docker.html.f45c96a5.js"><link rel="prefetch" href="/assets/Java基础.html.56267f30.js"><link rel="prefetch" href="/assets/Java容器.html.5139503a.js"><link rel="prefetch" href="/assets/JUC.html.ebe8f287.js"><link rel="prefetch" href="/assets/JVM.html.c448b42c.js"><link rel="prefetch" href="/assets/Linux.html.43840acf.js"><link rel="prefetch" href="/assets/MySQL.html.eba28d84.js"><link rel="prefetch" href="/assets/NIO与Netty.html.66d42188.js"><link rel="prefetch" href="/assets/index.html.f3cc61a2.js"><link rel="prefetch" href="/assets/Redis.html.d810a669.js"><link rel="prefetch" href="/assets/分布式与高性能高可用.html.a85c8cdb.js"><link rel="prefetch" href="/assets/操作系统.html.c2f0370c.js"><link rel="prefetch" href="/assets/智力题.html.4d751983.js"><link rel="prefetch" href="/assets/系统设计.html.c1542e9d.js"><link rel="prefetch" href="/assets/计算机网络.html.724e0903.js"><link rel="prefetch" href="/assets/设计模式.html.2465754d.js"><link rel="prefetch" href="/assets/article1.html.ac18bda1.js"><link rel="prefetch" href="/assets/article2.html.051f8867.js"><link rel="prefetch" href="/assets/article3.html.ebe7849b.js"><link rel="prefetch" href="/assets/article4.html.a4dbc976.js"><link rel="prefetch" href="/assets/article5.html.395a5403.js"><link rel="prefetch" href="/assets/article6.html.74c49cbf.js"><link rel="prefetch" href="/assets/article7.html.bf053e97.js"><link rel="prefetch" href="/assets/article8.html.7213c414.js"><link rel="prefetch" href="/assets/404.html.22aaa4fc.js"><link rel="prefetch" href="/assets/index.html.bd6ff77c.js"><link rel="prefetch" href="/assets/index.html.a7880d9d.js"><link rel="prefetch" href="/assets/index.html.f5f99f6a.js"><link rel="prefetch" href="/assets/index.html.561cd4cd.js"><link rel="prefetch" href="/assets/index.html.2b2206fe.js"><link rel="prefetch" href="/assets/index.html.ec6b7467.js"><link rel="prefetch" href="/assets/index.html.146ab8c4.js"><link rel="prefetch" href="/assets/index.html.f201f6e8.js"><link rel="prefetch" href="/assets/index.html.a1a6c5d4.js"><link rel="prefetch" href="/assets/index.html.61b33c23.js"><link rel="prefetch" href="/assets/index.html.8640e57f.js"><link rel="prefetch" href="/assets/index.html.c3d0fc1d.js"><link rel="prefetch" href="/assets/index.html.461f8cdf.js"><link rel="prefetch" href="/assets/index.html.1dea7bef.js"><link rel="prefetch" href="/assets/index.html.e6addda8.js"><link rel="prefetch" href="/assets/index.html.2638e7e9.js"><link rel="prefetch" href="/assets/index.html.5db2b8e8.js"><link rel="prefetch" href="/assets/index.html.cbff7fea.js"><link rel="prefetch" href="/assets/index.html.5ac21d40.js"><link rel="prefetch" href="/assets/index.html.c7acfbee.js"><link rel="prefetch" href="/assets/index.html.fb44feb1.js"><link rel="prefetch" href="/assets/index.html.d4e476c9.js"><link rel="prefetch" href="/assets/index.html.ec5764c9.js"><link rel="prefetch" href="/assets/index.html.d185c9f1.js"><link rel="prefetch" href="/assets/index.html.0867f7ab.js"><link rel="prefetch" href="/assets/index.html.2c3899c7.js"><link rel="prefetch" href="/assets/index.html.8a2aee35.js"><link rel="prefetch" href="/assets/index.html.130e4c85.js"><link rel="prefetch" href="/assets/index.html.7277b095.js"><link rel="prefetch" href="/assets/index.html.c074ddbd.js"><link rel="prefetch" href="/assets/index.html.e91a40c5.js"><link rel="prefetch" href="/assets/index.html.0b2b027d.js"><link rel="prefetch" href="/assets/index.html.6b602146.js"><link rel="prefetch" href="/assets/index.html.16d4af72.js"><link rel="prefetch" href="/assets/index.html.b8fc0dcc.js"><link rel="prefetch" href="/assets/index.html.9b3fcbd9.js"><link rel="prefetch" href="/assets/index.html.eeb89bf7.js"><link rel="prefetch" href="/assets/index.html.5114cd1e.js"><link rel="prefetch" href="/assets/index.html.b8354286.js"><link rel="prefetch" href="/assets/index.html.fcd579df.js"><link rel="prefetch" href="/assets/index.html.e743d320.js"><link rel="prefetch" href="/assets/index.html.b34f28e1.js"><link rel="prefetch" href="/assets/index.html.dd5dd927.js"><link rel="prefetch" href="/assets/index.html.7df41339.js"><link rel="prefetch" href="/assets/index.html.9de9b7ae.js"><link rel="prefetch" href="/assets/index.html.db158b25.js"><link rel="prefetch" href="/assets/index.html.fcab0b26.js"><link rel="prefetch" href="/assets/index.html.afada1db.js"><link rel="prefetch" href="/assets/index.html.8681058b.js"><link rel="prefetch" href="/assets/index.html.1c990d16.js"><link rel="prefetch" href="/assets/index.html.9563932e.js"><link rel="prefetch" href="/assets/404.4ba82410.js"><link rel="prefetch" href="/assets/Layout.67323a43.js"><link rel="prefetch" href="/assets/Slide.be972901.js"><link rel="prefetch" href="/assets/Blog.caaad5e4.js"><link rel="prefetch" href="/assets/giscus.es.63137db5.js"><link rel="prefetch" href="/assets/auto.esm.36809f22.js"><link rel="prefetch" href="/assets/index.daae04bf.js"><link rel="prefetch" href="/assets/index.1842ee54.js"><link rel="prefetch" href="/assets/mermaid.esm.min.ee1e0284.js"><link rel="prefetch" href="/assets/highlight.esm.d982e650.js"><link rel="prefetch" href="/assets/markdown.esm.832a189d.js"><link rel="prefetch" href="/assets/math.esm.a3f84b6f.js"><link rel="prefetch" href="/assets/notes.esm.3c361cb7.js"><link rel="prefetch" href="/assets/reveal.esm.b96f05d8.js"><link rel="prefetch" href="/assets/search.esm.80da4a02.js"><link rel="prefetch" href="/assets/zoom.esm.8514a202.js"><link rel="prefetch" href="/assets/photoswipe.esm.092fbc15.js">
  </head>
  <body>
    <div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="skip-link sr-only">Skip to content</a><!--]--><div class="theme-container has-toc"><!--[--><!--[--><header class="navbar"><div class="navbar-left"><button class="toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!----><a href="/zh/" class="brand"><img class="logo" src="/logo.svg" alt="主题演示"><!----><span class="site-name hide-in-pad">主题演示</span></a><!----></div><div class="navbar-center"><!----><nav class="nav-links"><div class="nav-item hide-in-mobile"><a href="/zh/" class="nav-link" aria-label="博客主页"><span class="icon iconfont icon-home" style=""></span>博客主页<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zh/home.html" class="nav-link" aria-label="项目主页"><span class="icon iconfont icon-home" style=""></span>项目主页<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zh/guide/" class="nav-link" aria-label="使用指南"><span class="icon iconfont icon-creative" style=""></span>使用指南<!----></a></div><div class="nav-item hide-in-mobile"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="博文"><span class="title"><span class="icon iconfont icon-edit" style=""></span>博文</span><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><h4 class="dropdown-subtitle"><span>文章 1-4</span></h4><ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/zh/posts/article/article1.html" class="nav-link" aria-label="文章 1"><span class="icon iconfont icon-edit" style=""></span>文章 1<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article2.html" class="nav-link" aria-label="文章 2"><span class="icon iconfont icon-edit" style=""></span>文章 2<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article3.html" class="nav-link" aria-label="文章 3"><span class="icon iconfont icon-edit" style=""></span>文章 3<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article4.html" class="nav-link" aria-label="文章 4"><span class="icon iconfont icon-edit" style=""></span>文章 4<!----></a></li></ul></li><li class="dropdown-item"><h4 class="dropdown-subtitle"><span>文章 5-12</span></h4><ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/zh/posts/article/article5.html" class="nav-link" aria-label="文章 5"><span class="icon iconfont icon-edit" style=""></span>文章 5<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article6.html" class="nav-link" aria-label="文章 6"><span class="icon iconfont icon-edit" style=""></span>文章 6<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article7.html" class="nav-link" aria-label="文章 7"><span class="icon iconfont icon-edit" style=""></span>文章 7<!----></a></li><li class="dropdown-subitem"><a href="/zh/posts/article/article8.html" class="nav-link" aria-label="文章 8"><span class="icon iconfont icon-edit" style=""></span>文章 8<!----></a></li></ul></li><li class="dropdown-item"><a href="/zh/posts/article9.html" class="nav-link" aria-label="文章 9"><span class="icon iconfont icon-edit" style=""></span>文章 9<!----></a></li><li class="dropdown-item"><a href="/zh/posts/article10.html" class="nav-link" aria-label="文章 10"><span class="icon iconfont icon-edit" style=""></span>文章 10<!----></a></li><li class="dropdown-item"><a href="/zh/posts/article11.html" class="nav-link" aria-label="文章 11"><span class="icon iconfont icon-edit" style=""></span>文章 11<!----></a></li><li class="dropdown-item"><a href="/zh/posts/article12.html" class="nav-link" aria-label="文章 12"><span class="icon iconfont icon-edit" style=""></span>文章 12<!----></a></li></ul></button></div></div><div class="nav-item hide-in-mobile"><a href="https://vuepress-theme-hope.github.io/v2/zh/" rel="noopener noreferrer" target="_blank" aria-label="主题文档" class="nav-link"><span class="icon iconfont icon-note" style=""></span>主题文档<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div></nav><!----></div><div class="navbar-right"><!----><div class="nav-item"><div class="dropdown-wrapper i18n-dropdown"><button class="dropdown-title" type="button" aria-label="选择语言"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon i18n-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="i18n icon" style="width:1rem;height:1rem;vertical-align:middle;"><path d="M379.392 460.8 494.08 575.488l-42.496 102.4L307.2 532.48 138.24 701.44l-71.68-72.704L234.496 460.8l-45.056-45.056c-27.136-27.136-51.2-66.56-66.56-108.544h112.64c7.68 14.336 16.896 27.136 26.112 35.84l45.568 46.08 45.056-45.056C382.976 312.32 409.6 247.808 409.6 204.8H0V102.4h256V0h102.4v102.4h256v102.4H512c0 70.144-37.888 161.28-87.04 210.944L378.88 460.8zM576 870.4 512 1024H409.6l256-614.4H768l256 614.4H921.6l-64-153.6H576zM618.496 768h196.608L716.8 532.48 618.496 768z"></path></svg><!--]--><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><a href="/" class="nav-link" aria-label="English"><!---->English<!----></a></li><li class="dropdown-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html" class="router-link-active router-link-exact-active nav-link active" aria-label="简体中文"><!---->简体中文<!----></a></li></ul></button></div></div><div class="nav-item"><a class="repo-link" href="https://gitee.com/changluJava/personal-reading" target="_blank" rel="noopener noreferrer" aria-label="Gitee"><svg xmlns="http://www.w3.org/2000/svg" class="icon gitee-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="gitee icon" style="width:1.25rem;height:1.25rem;vertical-align:middle;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm242.97-533.34H482.39a23.7 23.7 0 0 0-23.7 23.7l-.03 59.28c0 13.08 10.59 23.7 23.7 23.7h165.96a23.7 23.7 0 0 1 23.7 23.7v11.85a71.1 71.1 0 0 1-71.1 71.1H375.71a23.7 23.7 0 0 1-23.7-23.7V423.11a71.1 71.1 0 0 1 71.1-71.1h331.8a23.7 23.7 0 0 0 23.7-23.7l.06-59.25a23.73 23.73 0 0 0-23.7-23.73H423.11a177.78 177.78 0 0 0-177.78 177.75v331.83c0 13.08 10.62 23.7 23.7 23.7h349.62a159.99 159.99 0 0 0 159.99-159.99V482.33a23.7 23.7 0 0 0-23.7-23.7z"></path></svg></a></div><div class="nav-item hide-in-mobile"><button id="appearance-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="light icon" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><!----><!----><button class="toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span class="button-container"><span class="button-top"></span><span class="button-middle"></span><span class="button-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow left"></span></div><aside class="sidebar"><!--[--><!----><!--]--><ul class="sidebar-links"><li><!--[--><a href="/zh/" class="nav-link sidebar-link sidebar-page" aria-label="博客主页"><span class="icon iconfont icon-home" style=""></span>博客主页<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/home.html" class="nav-link sidebar-link sidebar-page" aria-label="项目主页"><span class="icon iconfont icon-home" style=""></span>项目主页<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/slide" class="nav-link sidebar-link sidebar-page" aria-label="幻灯片"><!---->幻灯片<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><span class="icon iconfont icon-creative" style=""></span><a href="/zh/interview/" class="title">面试指南</a><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><a href="/zh/interview/Docker.html" class="nav-link sidebar-link sidebar-page" aria-label="Docker"><span class="icon iconfont icon-lock" style=""></span>Docker<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Java%E5%9F%BA%E7%A1%80.html" class="nav-link sidebar-link sidebar-page" aria-label="JAVA"><span class="icon iconfont icon-lock" style=""></span>JAVA<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Java%E5%AE%B9%E5%99%A8.html" class="nav-link sidebar-link sidebar-page" aria-label="Java容器"><span class="icon iconfont icon-lock" style=""></span>Java容器<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/JUC.html" class="nav-link sidebar-link sidebar-page" aria-label="JUC"><span class="icon iconfont icon-lock" style=""></span>JUC<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/JVM.html" class="nav-link sidebar-link sidebar-page" aria-label="JVM"><span class="icon iconfont icon-lock" style=""></span>JVM<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Linux.html" class="nav-link sidebar-link sidebar-page" aria-label="Linux"><span class="icon iconfont icon-lock" style=""></span>Linux<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/MySQL.html" class="nav-link sidebar-link sidebar-page" aria-label="MySQL"><span class="icon iconfont icon-lock" style=""></span>MySQL<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/NIO%E4%B8%8ENetty.html" class="nav-link sidebar-link sidebar-page" aria-label="Netty"><span class="icon iconfont icon-lock" style=""></span>Netty<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/Redis.html" class="nav-link sidebar-link sidebar-page" aria-label="Redis"><span class="icon iconfont icon-lock" style=""></span>Redis<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html" class="router-link-active router-link-exact-active nav-link active sidebar-link sidebar-page active" aria-label="主流框架"><span class="icon iconfont icon-lock" style=""></span>主流框架<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#javaweb" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="JavaWeb"><!---->JavaWeb<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、filter、intercepter以及aop在整个框架中的顺序" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、filter、intercepter以及AOP在整个框架中的顺序"><!---->1、filter、intercepter以及AOP在整个框架中的顺序<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、servlet" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、servlet"><!---->2、servlet<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、cookie与session" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、cookie与session"><!---->3、cookie与session<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#spring" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="Spring"><!---->Spring<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、什么是-spring-框架" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、什么是 Spring 框架?"><!---->1、什么是 Spring 框架?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、列举一些重要的-spring-模块" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、列举一些重要的 Spring 模块？"><!---->2、列举一些重要的 Spring 模块？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、spring-spring-mvc-spring-boot-之间什么关系" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、Spring,Spring MVC,Spring Boot 之间什么关系?"><!---->3、Spring,Spring MVC,Spring Boot 之间什么关系?<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_4、spring-ioc-aop" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="4、Spring IOC &amp; AOP"><!---->4、Spring IOC &amp; AOP<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_5、spring-bean" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="5、Spring Bean"><!---->5、Spring Bean<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_6、spring的事务" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="6、Spring的事务"><!---->6、Spring的事务<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_7、spring的循环依赖" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="7、Spring的循环依赖"><!---->7、Spring的循环依赖<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#springmvc" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="SpringMVC"><!---->SpringMVC<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、简述springmvc的工作原理" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、简述SpringMVC的工作原理"><!---->1、简述SpringMVC的工作原理<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、springmvc的常用注解" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、SpringMVC的常用注解"><!---->2、SpringMVC的常用注解<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、异常处理" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、异常处理"><!---->3、异常处理<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_4、拦截器" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="4、拦截器"><!---->4、拦截器<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_5、说说自己对于-spring-mvc-了解" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="5、说说自己对于 Spring MVC 了解?"><!---->5、说说自己对于 Spring MVC 了解?<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#mybatis" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="Mybatis"><!---->Mybatis<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#使用到的设计模式" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="使用到的设计模式"><!---->使用到的设计模式<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、mybatis-中-和-的区别" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、Mybatis 中#和$的区别"><!---->1、Mybatis 中#和$的区别<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、mybatis的编程步骤" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、Mybatis的编程步骤？"><!---->2、Mybatis的编程步骤？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、一级缓存与二级缓存" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="3、一级缓存与二级缓存"><!---->3、一级缓存与二级缓存<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_4、xml-映射文件中-除了常见的-select-insert-update-delete-标签之外-还有哪些标签" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="4、Xml 映射文件中，除了常见的 select|insert|update|delete 标签之外，还有哪些标签？"><!---->4、Xml 映射文件中，除了常见的 select|insert|update|delete 标签之外，还有哪些标签？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_5、最佳实践中-通常一个-xml-映射文件-都会写一个-dao-接口与之对应-请问-这个-dao-接口的工作原理是什么-dao-接口里的方法-参数不同时-方法能重载吗" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="5、最佳实践中，通常一个 Xml 映射文件，都会写一个 Dao 接口与之对应，请问，这个 Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？"><!---->5、最佳实践中，通常一个 Xml 映射文件，都会写一个 Dao 接口与之对应，请问，这个 Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_6、mybatis-是如何进行分页的-分页插件的原理是什么" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="6、MyBatis 是如何进行分页的？分页插件的原理是什么？"><!---->6、MyBatis 是如何进行分页的？分页插件的原理是什么？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_7、简述-mybatis-的插件运行原理-以及如何编写一个插件。" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="7、简述 MyBatis 的插件运行原理，以及如何编写一个插件。"><!---->7、简述 MyBatis 的插件运行原理，以及如何编写一个插件。<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_8、mybatis-执行批量插入-能返回数据库主键列表吗" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="8、MyBatis 执行批量插入，能返回数据库主键列表吗？"><!---->8、MyBatis 执行批量插入，能返回数据库主键列表吗？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_9、mybatis-动态-sql-是做什么的-都有哪些动态-sql-能简述一下动态-sql-的执行原理不" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="9、MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？"><!---->9、MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_10、mybatis-是如何将-sql-执行结果封装为目标对象并返回的-都有哪些映射形式" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="10、MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？"><!---->10、MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_11、mybatis-能执行一对一、一对多的关联查询吗-都有哪些实现方式-以及它们之间的区别。" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="11、MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别。"><!---->11、MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别。<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_12、mybatis-是否支持延迟加载-如果支持-它的实现原理是什么" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="12、MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？"><!---->12、MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_13、mybatis-的-xml-映射文件中-不同的-xml-映射文件-id-是否可以重复" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="13、MyBatis 的 Xml 映射文件中，不同的 Xml 映射文件，id 是否可以重复？"><!---->13、MyBatis 的 Xml 映射文件中，不同的 Xml 映射文件，id 是否可以重复？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_14、mybatis-中如何执行批处理" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="14、MyBatis 中如何执行批处理？"><!---->14、MyBatis 中如何执行批处理？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_15、mybatis-中如何指定使用哪一种-executor-执行器" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="15、MyBatis 中如何指定使用哪一种 Executor 执行器？"><!---->15、MyBatis 中如何指定使用哪一种 Executor 执行器？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_16、mybatis-是否可以映射-enum-枚举类" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="16、MyBatis 是否可以映射 Enum 枚举类？"><!---->16、MyBatis 是否可以映射 Enum 枚举类？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_17、mybatis-映射文件中-如果-a-标签通过-include-引用了-b-标签的内容-请问-b-标签能否定义在-a-标签的后面-还是说必须定义在-a-标签的前面" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="17、MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？"><!---->17、MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_18、简述-mybatis-的-xml-映射文件和-mybatis-内部数据结构之间的映射关系" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="18、简述 MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系？"><!---->18、简述 MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系？<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_19、为什么说-mybatis-是半自动-orm-映射工具-它与全自动的区别在哪里" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="19、为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？"><!---->19、为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#springboot" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="SpringBoot"><!---->SpringBoot<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、自动装配原理-自定义starter" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="1、自动装配原理（自定义starter）"><!---->1、自动装配原理（自定义starter）<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、spring、springmvc、springboot区别" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="2、spring、springmvc、springboot区别"><!---->2、spring、springmvc、springboot区别<!----></a><ul class="sidebar-sub-headers"></ul></li></ul></li></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E9%AB%98%E6%80%A7%E8%83%BD%E9%AB%98%E5%8F%AF%E7%94%A8.html" class="nav-link sidebar-link sidebar-page" aria-label="分布式"><span class="icon iconfont icon-lock" style=""></span>分布式<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.html" class="nav-link sidebar-link sidebar-page" aria-label="操作系统"><span class="icon iconfont icon-lock" style=""></span>操作系统<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E6%99%BA%E5%8A%9B%E9%A2%98.html" class="nav-link sidebar-link sidebar-page" aria-label="智力题"><span class="icon iconfont icon-lock" style=""></span>智力题<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1.html" class="nav-link sidebar-link sidebar-page" aria-label="系统设计"><span class="icon iconfont icon-lock" style=""></span>系统设计<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.html" class="nav-link sidebar-link sidebar-page" aria-label="计算机网络"><span class="icon iconfont icon-lock" style=""></span>计算机网络<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/interview/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.html" class="nav-link sidebar-link sidebar-page" aria-label="设计模式"><!---->设计模式<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading clickable"><span class="icon iconfont icon-creative" style=""></span><a href="/zh/guide/" class="title">如何使用</a><!----></p><ul class="sidebar-links"><li><!--[--><a href="/zh/guide/page.html" class="nav-link sidebar-link sidebar-page" aria-label="页面配置"><span class="icon iconfont icon-page" style=""></span>页面配置<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/guide/markdown.html" class="nav-link sidebar-link sidebar-page" aria-label="Markdown 展示"><span class="icon iconfont icon-markdown" style=""></span>Markdown 展示<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/guide/disable.html" class="nav-link sidebar-link sidebar-page" aria-label="布局与功能禁用"><span class="icon iconfont icon-config" style=""></span>布局与功能禁用<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/guide/encrypt.html" class="nav-link sidebar-link sidebar-page" aria-label="密码加密的文章"><span class="icon iconfont icon-lock" style=""></span>密码加密的文章<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading"><span class="icon iconfont icon-note" style=""></span><span class="title">文章</span><!----></p><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 1-4</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 5-12</span><!----></p><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 5-8</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><p class="sidebar-heading"><span class="icon iconfont icon-note" style=""></span><span class="title">文章 9-12</span><!----></p><ul class="sidebar-links"><li><!--[--><a href="/zh/posts/article9.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 9"><span class="icon iconfont icon-edit" style=""></span>文章 9<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/posts/article10.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 10"><span class="icon iconfont icon-edit" style=""></span>文章 10<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/posts/article11.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 11"><span class="icon iconfont icon-edit" style=""></span>文章 11<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/zh/posts/article12.html" class="nav-link sidebar-link sidebar-page" aria-label="文章 12"><span class="icon iconfont icon-edit" style=""></span>文章 12<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li></ul></section><!--]--></li></ul></section><!--]--></li></ul><!--[--><!----><!--]--></aside><!--[--><main class="page" id="main-content"><!--[--><!----><nav class="breadcrumb disable"></nav><div class="page-title"><h1><span class="icon iconfont icon-lock" style=""></span>主流框架</h1><div class="page-info"><span class="author-info" aria-label="作者🖊" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon author-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="author icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"></path></svg><span><a class="author-item" href="https://changlu.blog.csdn.net" target="_blank" rel="noopener noreferrer">长路</a></span><span property="author" content="长路"></span></span><!----><!----><span class="category-info" aria-label="分类🌈" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon category-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="category icon"><path d="M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"></path></svg><ul class="categories-wrapper"><li class="category category8 clickable" role="navigation">面试题</li><meta property="articleSection" content="面试题"></ul></span><span aria-label="标签🏷" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon tag-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="tag icon"><path d="M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"></path></svg><ul class="tags-wrapper"><li class="tag tag3 clickable" role="navigation">主流框架</li></ul><meta property="keywords" content="主流框架"></span><span class="reading-time-info" aria-label="阅读时间⌛" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon timer-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="timer icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"></path></svg><span>大约 41 分钟</span><meta property="timeRequired" content="PT41M"></span></div><hr></div><div class="toc-place-holder"><aside id="toc"><div class="toc-header">此页内容</div><div class="toc-wrapper"><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#javaweb" class="router-link-active router-link-exact-active toc-link level2">JavaWeb</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、filter、intercepter以及aop在整个框架中的顺序" class="router-link-active router-link-exact-active toc-link level3">1、filter、intercepter以及AOP在整个框架中的顺序</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、servlet" class="router-link-active router-link-exact-active toc-link level3">2、servlet</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、cookie与session" class="router-link-active router-link-exact-active toc-link level3">3、cookie与session</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#spring" class="router-link-active router-link-exact-active toc-link level2">Spring</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、什么是-spring-框架" class="router-link-active router-link-exact-active toc-link level3">1、什么是 Spring 框架?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、列举一些重要的-spring-模块" class="router-link-active router-link-exact-active toc-link level3">2、列举一些重要的 Spring 模块？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、spring-spring-mvc-spring-boot-之间什么关系" class="router-link-active router-link-exact-active toc-link level3">3、Spring,Spring MVC,Spring Boot 之间什么关系?</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_4、spring-ioc-aop" class="router-link-active router-link-exact-active toc-link level3">4、Spring IOC &amp; AOP</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_5、spring-bean" class="router-link-active router-link-exact-active toc-link level3">5、Spring Bean</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_6、spring的事务" class="router-link-active router-link-exact-active toc-link level3">6、Spring的事务</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_7、spring的循环依赖" class="router-link-active router-link-exact-active toc-link level3">7、Spring的循环依赖</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#springmvc" class="router-link-active router-link-exact-active toc-link level2">SpringMVC</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、简述springmvc的工作原理" class="router-link-active router-link-exact-active toc-link level3">1、简述SpringMVC的工作原理</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、springmvc的常用注解" class="router-link-active router-link-exact-active toc-link level3">2、SpringMVC的常用注解</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、异常处理" class="router-link-active router-link-exact-active toc-link level3">3、异常处理</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_4、拦截器" class="router-link-active router-link-exact-active toc-link level3">4、拦截器</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_5、说说自己对于-spring-mvc-了解" class="router-link-active router-link-exact-active toc-link level3">5、说说自己对于 Spring MVC 了解?</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#mybatis" class="router-link-active router-link-exact-active toc-link level2">Mybatis</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#使用到的设计模式" class="router-link-active router-link-exact-active toc-link level3">使用到的设计模式</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、mybatis-中-和-的区别" class="router-link-active router-link-exact-active toc-link level3">1、Mybatis 中#和$的区别</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、mybatis的编程步骤" class="router-link-active router-link-exact-active toc-link level3">2、Mybatis的编程步骤？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_3、一级缓存与二级缓存" class="router-link-active router-link-exact-active toc-link level3">3、一级缓存与二级缓存</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_4、xml-映射文件中-除了常见的-select-insert-update-delete-标签之外-还有哪些标签" class="router-link-active router-link-exact-active toc-link level3">4、Xml 映射文件中，除了常见的 select|insert|update|delete 标签之外，还有哪些标签？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_5、最佳实践中-通常一个-xml-映射文件-都会写一个-dao-接口与之对应-请问-这个-dao-接口的工作原理是什么-dao-接口里的方法-参数不同时-方法能重载吗" class="router-link-active router-link-exact-active toc-link level3">5、最佳实践中，通常一个 Xml 映射文件，都会写一个 Dao 接口与之对应，请问，这个 Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_6、mybatis-是如何进行分页的-分页插件的原理是什么" class="router-link-active router-link-exact-active toc-link level3">6、MyBatis 是如何进行分页的？分页插件的原理是什么？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_7、简述-mybatis-的插件运行原理-以及如何编写一个插件。" class="router-link-active router-link-exact-active toc-link level3">7、简述 MyBatis 的插件运行原理，以及如何编写一个插件。</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_8、mybatis-执行批量插入-能返回数据库主键列表吗" class="router-link-active router-link-exact-active toc-link level3">8、MyBatis 执行批量插入，能返回数据库主键列表吗？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_9、mybatis-动态-sql-是做什么的-都有哪些动态-sql-能简述一下动态-sql-的执行原理不" class="router-link-active router-link-exact-active toc-link level3">9、MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_10、mybatis-是如何将-sql-执行结果封装为目标对象并返回的-都有哪些映射形式" class="router-link-active router-link-exact-active toc-link level3">10、MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_11、mybatis-能执行一对一、一对多的关联查询吗-都有哪些实现方式-以及它们之间的区别。" class="router-link-active router-link-exact-active toc-link level3">11、MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别。</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_12、mybatis-是否支持延迟加载-如果支持-它的实现原理是什么" class="router-link-active router-link-exact-active toc-link level3">12、MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_13、mybatis-的-xml-映射文件中-不同的-xml-映射文件-id-是否可以重复" class="router-link-active router-link-exact-active toc-link level3">13、MyBatis 的 Xml 映射文件中，不同的 Xml 映射文件，id 是否可以重复？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_14、mybatis-中如何执行批处理" class="router-link-active router-link-exact-active toc-link level3">14、MyBatis 中如何执行批处理？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_15、mybatis-中如何指定使用哪一种-executor-执行器" class="router-link-active router-link-exact-active toc-link level3">15、MyBatis 中如何指定使用哪一种 Executor 执行器？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_16、mybatis-是否可以映射-enum-枚举类" class="router-link-active router-link-exact-active toc-link level3">16、MyBatis 是否可以映射 Enum 枚举类？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_17、mybatis-映射文件中-如果-a-标签通过-include-引用了-b-标签的内容-请问-b-标签能否定义在-a-标签的后面-还是说必须定义在-a-标签的前面" class="router-link-active router-link-exact-active toc-link level3">17、MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_18、简述-mybatis-的-xml-映射文件和-mybatis-内部数据结构之间的映射关系" class="router-link-active router-link-exact-active toc-link level3">18、简述 MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系？</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_19、为什么说-mybatis-是半自动-orm-映射工具-它与全自动的区别在哪里" class="router-link-active router-link-exact-active toc-link level3">19、为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？</a></li><!----><!--]--></ul><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#springboot" class="router-link-active router-link-exact-active toc-link level2">SpringBoot</a></li><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_1、自动装配原理-自定义starter" class="router-link-active router-link-exact-active toc-link level3">1、自动装配原理（自定义starter）</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/zh/interview/%E4%B8%BB%E6%B5%81%E6%A1%86%E6%9E%B6.html#_2、spring、springmvc、springboot区别" class="router-link-active router-link-exact-active toc-link level3">2、spring、springmvc、springboot区别</a></li><!----><!--]--></ul><!--]--></ul></div></aside></div><!----><div class="theme-hope-content"><h1 id="主流框架" tabindex="-1"><a class="header-anchor" href="#主流框架" aria-hidden="true">#</a> 主流框架</h1><h2 id="javaweb" tabindex="-1"><a class="header-anchor" href="#javaweb" aria-hidden="true">#</a> JavaWeb</h2><h3 id="_1、filter、intercepter以及aop在整个框架中的顺序" tabindex="-1"><a class="header-anchor" href="#_1、filter、intercepter以及aop在整个框架中的顺序" aria-hidden="true">#</a> 1、filter、intercepter以及AOP在整个框架中的顺序</h3><blockquote><p><a href="https://blog.csdn.net/meser88/article/details/120184863?spm=1001.2101.3001.6650.1&amp;utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-120184863-blog-106215972.pc_relevant_antiscanv2&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-120184863-blog-106215972.pc_relevant_antiscanv2&amp;utm_relevant_index=2" target="_blank" rel="noopener noreferrer">spring中过滤器（filter）、拦截器（interceptor）和切面（aop）的执行顺序<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>Filter (do.chain...)-&gt; Interceptor ...-&gt;<a href="https://so.csdn.net/so/search?q=AOP&amp;spm=1001.2101.3001.7020" target="_blank" rel="noopener noreferrer">AOP<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>(被spring管理的bean)...-&gt;Interceptor...-&gt;Filter</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TimeFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>
    
    <span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    
    <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token comment">//向下执行</span>
        chain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>request<span class="token punctuation">,</span> response<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
    <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TimeInterceptor</span> <span class="token keyword">implements</span> <span class="token class-name">HandlerInterceptor</span> <span class="token punctuation">{</span>
    
    
    <span class="token function">preHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span><span class="token comment">//true表示向后执行</span>
    <span class="token punctuation">}</span>
    
    <span class="token function">postHandle</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        
    <span class="token function">afterCompletion</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Aspect</span>
<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TimeAspect</span> <span class="token punctuation">{</span>
 
	<span class="token annotation punctuation">@Before</span><span class="token punctuation">(</span><span class="token string">&quot;execution(public * com.hu.web.controller.UserController.*(..))&quot;</span><span class="token punctuation">)</span>
	<span class="token keyword">public</span> <span class="token class-name">Object</span> <span class="token function">handlerControllerMethod</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Throwable</span> <span class="token punctuation">{</span>
		<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;time aspect start&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>			
		<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
	<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181326312.png" alt="image-20220618132626263" loading="lazy"></p><h3 id="_2、servlet" tabindex="-1"><a class="header-anchor" href="#_2、servlet" aria-hidden="true">#</a> 2、servlet</h3><blockquote><p>参考文章：<a href="https://www.cnblogs.com/liuxiaochong/p/13528373.html" target="_blank" rel="noopener noreferrer">servlet的生命周期和工作原理介绍<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p><code>servlet</code>是单例多线程。</p><p><code>Servlet</code>执行流程：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181327839.png" alt="img" loading="lazy"></p><p><code>Servlet</code>生命周期：Servlet 加载—&gt;实例化—&gt;服务—&gt;销毁。即构造器创建实例对象-init()-service()-destory()，可以说初始化、响应请求、终止阶段</p><ul><li><code>init()</code>：在Servlet的生命周期中执行一次init()方法，是在服务器装入servlet时执行。负责初始化Servlet对象，无论多少客户机访问servlet，都不会重复执行init()方法。</li><li><code>service()</code>：Servlet的核心，负责响应客户的请求，当请求用户到达Servlet容器时，创建特定于这个请求的ServletRequest对象和ServletResponse对象，然后调用Servlet的service方法。service方法从ServletRequest对象获得客户请求信息，处理该请求，并通过ServletResponse对象向客户返回响应信息。</li><li><code>destory()</code>：当WEB应用被终止，或Servlet容器终止运行，或Servlet容器重新装载Servlet新实例时，Servlet容器会先调用Servlet的destroy()方法，在destroy()方法中可以释放掉Servlet所占用的资源。</li></ul><blockquote><p>与Tomcat结合时的步骤</p></blockquote><p>1、Web Client 向Servlet容器（Tomcat）发出Http请求</p><p>2、Servlet容器接收Web Client的请求</p><p>3、Servlet容器创建一个HttpRequest对象，将Web Client请求的信息封装到这个对象中。</p><p>4、Servlet容器创建一个HttpResponse对象</p><p>5、Servlet容器调用HttpServlet对象的service方法，把HttpRequest对象与HttpResponse对象作为参数传给HttpServlet 对象。</p><p>6、HttpServlet调用HttpRequest对象的有关方法，获取Http请求信息。</p><p>7、HttpServlet调用HttpResponse对象的有关方法，生成响应数据。</p><h3 id="_3、cookie与session" tabindex="-1"><a class="header-anchor" href="#_3、cookie与session" aria-hidden="true">#</a> 3、cookie与session</h3><p><strong>参考文章</strong>：<a href="https://www.cnblogs.com/l199616j/p/11195667.html" target="_blank" rel="noopener noreferrer">cookie和session的详解与区别<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p>常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份，Session通过在服务器端记录信息确定用户身份。cookie存储在客户端，session存储在服务端。</p><blockquote><p>cookie</p></blockquote><p>Cookie弥补HTTP协议无状态的不足。在Session出现之前，基本上所有的网站都采用Cookie来跟踪会话。</p><p>Cookie是web服务器发送给浏览器的一块信息，浏览器会在本地的文件中给每一个web服务器存储cookie。之后浏览器给特定的web服务器发送请求时，同时会发送所有为该服务器存储的cookie。</p><p>Cookie的有效期：单位为秒，可进行设置，无论客户端关闭电脑还是浏览器，下次访问指定服务器该cookie依旧有效。</p><p>Cookie可实现永久登录：即将用户名与密码加密到cookie中，实现不访问数据库即可登陆。</p><br><blockquote><p>session</p></blockquote><p>Session是服务器端使用的一种记录客户端状态的机制，相较于cookie更简单一些，但是也相应的增加了服务器的存储压力。一般使用session来实现用户登录。</p><p>Session 是存储在 web 服务器端的一块信息。session 对象存储特定用户会话所需的属性及配置信息。当用户在应用程序的 Web 页之间跳转时，存储在 Session 对象中的变量将不会丢失，而是在整个用户会话中一直存在下去。</p><p><strong>Session的技术内幕</strong>：当客户端第一次访问服务器时调用getSession()，会创建一个session对象，与此同时会创建一个cookie(key值为JSESSIONID，value为刚创建session的id值)，下一次客户端再次访问时就会携带该cookie，通过该cookie的value值服务器会在内存中找到对应的sesson对象，通过getSession()即可获取到。</p><p><strong>Session生命周期</strong>：session一般放置在内存中，一旦生成，只要用户继续访问服务器(无论是否读写session)就会不断更新session的最后访问时间。tomcat中session默认时间为20分钟，超过20分钟后就会失效，可进行服务器xml配置或者程序修改。</p><br><blockquote><p>cookie与session的不同点</p></blockquote><p>1、存放位置：cookie数据存放在客户的浏览器上，session数据放在服务器上。</p><p>2、是否安全：cookie不是很安全，别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。</p><p>3、保存数据：单个cookie值保存数据不能超过4K，大多数浏览器最多保存20个cookie；session没有存储数量的显示，存储大小也没有限制。</p><p>4、生命周期：对于cookie可以预先设置生命周期或永久保存本地文件；对于session，浏览器一关session就消失了，因为浏览器一关该cookie就会被销毁掉(最大存活周期为session)，严格说此时在服务器中的session无效(浏览器没有对应保存的session id了)，一旦等待时间达到就会销毁。</p><h2 id="spring" tabindex="-1"><a class="header-anchor" href="#spring" aria-hidden="true">#</a> Spring</h2><h3 id="_1、什么是-spring-框架" tabindex="-1"><a class="header-anchor" href="#_1、什么是-spring-框架" aria-hidden="true">#</a> 1、什么是 Spring 框架?</h3><p>Spring 框架指的都是 Spring Framework，它是很多模块的集合，使用这些模块可以很方便地协助我们进行开发。</p><p>包含：最核心的是<code>IOC</code>与<code>AOP</code>。可以很方便的访问数据库，包含jdbc template，以及快速集成第三方组件（电子邮件，任务，调度，缓存等等）、支持单元测试，支持restful应用程序的开发。</p><h3 id="_2、列举一些重要的-spring-模块" tabindex="-1"><a class="header-anchor" href="#_2、列举一些重要的-spring-模块" aria-hidden="true">#</a> 2、列举一些重要的 Spring 模块？</h3><p>在 5.x 版本中，Web 模块的 Portlet 组件已废弃，此时增加了用于异步响应式处理的 WebFlux 组件。</p><p>包含模块如下：</p><ul><li><strong>Spring Core：核心模块</strong>， Spring 其他所有的功能基本都需要依赖于该模块，主要提供<code>IoC</code>依赖注入功能的支持。</li><li>Spring Aspects：集成AspectJ集成模块。</li><li><strong>Spring AOP：提供面向切面编程。</strong></li><li>Spring Data Access/Integration ：包含五个模块 <ul><li>spring-jdbc：对数据库访问的抽象 JDBC。</li><li><strong>spring-tx：提供对事务的支持。</strong></li><li>spring-orm：提供对 Hibernate 等 ORM 框架的支持。</li><li>spring-oxm：提供对 Castor 等 OXM 框架的支持。</li><li>spring-jms：Java 消息服务。</li></ul></li><li>Spring Web：包含四个模块 <ul><li><strong>spring-web ：对 Web 功能的实现提供一些最基础的支持</strong></li><li><strong>spring-webmvc ： 提供对 Spring MVC 的实现。</strong></li><li>spring-websocket ： 提供了对 WebSocket 的支持，WebSocket 可以让客户端和服务端进行双向通信。</li><li>spring-webflux ：提供对 WebFlux 的支持。WebFlux 是 Spring Framework 5.0 中引入的新的响应式框架。与 Spring MVC 不同，它不需要 Servlet API，是完全异步.</li></ul></li><li>Spring Test：提倡测试驱动开发（TDD），控制反转 (IoC)的帮助，单元测试和集成测试变得更简单。</li></ul><h3 id="_3、spring-spring-mvc-spring-boot-之间什么关系" tabindex="-1"><a class="header-anchor" href="#_3、spring-spring-mvc-spring-boot-之间什么关系" aria-hidden="true">#</a> 3、Spring,Spring MVC,Spring Boot 之间什么关系?</h3><p>Spring中最核心的是Spring-Core（主要<strong>提供 IoC 依赖注入功能</strong>的支持） 模块， Spring 中的其他模块（比如 Spring MVC）的功能实现基本都需要依赖于该模块。</p><p>Spring MVC 是 Spring 中的一个很重要的模块，主要赋予 Spring <strong>快速构建 MVC 架构的 Web 程序的能力</strong>。</p><ul><li>MVC 是模型(Model)、视图(View)、控制器(Controller)的简写，其核心思想是通过将业务逻辑、数据、显示分离来组织代码。</li></ul><p>由于Spring环境的配置以及集成其他框架繁杂的配置，SpringBoot诞生了：<strong>核心是简化Spring配置</strong>。</p><h3 id="_4、spring-ioc-aop" tabindex="-1"><a class="header-anchor" href="#_4、spring-ioc-aop" aria-hidden="true">#</a> 4、Spring IOC &amp; AOP</h3><h4 id="总结ioc与aop" tabindex="-1"><a class="header-anchor" href="#总结ioc与aop" aria-hidden="true">#</a> 总结IOC与AOP</h4><p>Spring 是一个开源框架，Spring 是一个 IOC(控制反转) 和 AOP(面向切面)容器框架。这两个模块是其中的核心。</p><blockquote><p>IOC(控制反转)：IOC容器本质上就是一个map(key-value)，里面存放了各种对象。控制反转指的是通过IOC容器来进行操作。</p></blockquote><p>曾经我们要获取一个对象需要使用new来进行手动创建对象，而在Spring的IOC(控制反转)模式中，将指定对象实例化操作交给了IOC容器进行，通过使用工厂模式来进行创建。想要获取对象时，通过IOC容器来统一拿取。</p><p>对于<strong>依赖注入</strong>(DI)，IoC容器在运行期间，动态地将某种依赖关系注入到对象之中。例如Spring使用javabean中的set方法或者构造器为我们在创建所需对象时将其属性自动设置所需要的值的过程。</p><br><blockquote><p>AOP(面向切面)</p></blockquote><p>我们将一个个的对象某些类似的方面横向抽成一个切面，对这个切面进行一些如权限控制、记录日志、黑名单等操作，这个过程就是面向切面编程的思想。</p><p>底层采用<code>JDK</code>动态代理以及<code>CGLIB</code>方式来进行实现动态代理。</p><p>在<code>AOP</code>中包含五个通知：前置通知、环绕通知、后置通知、最终通知、异常通知。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181618314.png" alt="image-20210523152500075" loading="lazy"></p><hr><h4 id="_1、谈谈自己对于-spring-ioc-的了解" tabindex="-1"><a class="header-anchor" href="#_1、谈谈自己对于-spring-ioc-的了解" aria-hidden="true">#</a> 1、谈谈自己对于 Spring IoC 的了解</h4><p><strong>IoC（Inverse of Control:控制反转）</strong> 是一种设计思想，而不是一个具体的技术实现。IoC 的思想就是将原本在程序中手动创建对象的控制权，交由 Spring 框架来管理。</p><ul><li>不是只有Spring才有IOC，其他语言中也有应用。</li></ul><p><strong>为什么叫控制反转？</strong></p><ul><li><strong>控制</strong> ：指的是对象创建（实例化、管理）的权力。</li><li><strong>反转</strong> ：控制权交给外部环境（Spring 框架、IoC 容器）。</li></ul><p>也就是将创建以及获取实例的过程交给IOC容器来为我们进行操作：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181347468.png" alt="image-20220618134727416" loading="lazy"></p><p><strong>核心</strong>：将<strong>对象之间的相互依赖关系交给 IoC 容器来管理</strong>，并由 IoC 容器完成对象的注入。这样可以很大程度上简化应用的开发，把应用从复杂的依赖关系中解放出来。</p><p><strong>本质</strong>：在 Spring 中， IoC 容器是 Spring 用来实现 IoC 的载体， IoC 容器实际上就是个 <strong>Map（key，value）</strong>，Map 中存放的是各种对象。</p><h4 id="_2、谈自己对于-aop-的了解" tabindex="-1"><a class="header-anchor" href="#_2、谈自己对于-aop-的了解" aria-hidden="true">#</a> 2、谈自己对于 AOP 的了解</h4><p>AOP(Aspect-Oriented Programming:面向切面编程)：通过切面编程的方式来为某些业务模块提供共同调用的方法代码，例如事务处理、日志管理、权限控制等。从而减少系统的重复代码，降低模块间的耦合度，并有利于未来的可拓展性和可维护性。</p><p>Spring中的两个AOP代理方式：基于动态代理</p><ul><li>实现了某个接口，那么 Spring AOP 会使用 <strong>JDK Proxy</strong>，去创建代理对象。</li><li>对于没有实现接口的对象， 会使用 <strong>Cglib</strong> 生成一个被代理对象的子类来作为代理。</li></ul><p>当然你也可以使用 <strong>AspectJ</strong> ！Spring AOP 已经集成了 AspectJ ，AspectJ 应该算的上是 Java 生态系统中最完整的 AOP 框架了。</p><h4 id="_3、spring-aop-和-aspectj-aop-有什么区别" tabindex="-1"><a class="header-anchor" href="#_3、spring-aop-和-aspectj-aop-有什么区别" aria-hidden="true">#</a> 3、Spring AOP 和 AspectJ AOP 有什么区别？</h4><blockquote><p><a href="https://jiayoudangdang.blog.csdn.net/article/details/123297362?spm=1001.2101.3001.6650.1&amp;utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-123297362-blog-121803976.pc_relevant_blogantidownloadv1&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1-123297362-blog-121803976.pc_relevant_blogantidownloadv1&amp;utm_relevant_index=2" target="_blank" rel="noopener noreferrer">Spring AOP and AspectJ AOP 有什么区别？【重点】【很详细并且清晰】<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>Spring AOP 属于<strong>运行时增强</strong>，而 <strong>AspectJ 是编译时增强</strong>。</p><p>Spring AOP 基于代理(Proxying)，而 AspectJ 基于字节码操作(Bytecode Manipulation)。</p><p><strong>两者比较</strong>：</p><ul><li>AspectJ 相比于 Spring AOP 功能更加强大，但是 Spring AOP 相对来说更简单。</li><li>如果我们的切面比较少，那么两者性能差异不大。但是，当切面太多的话，最好选择 AspectJ ，它比 Spring AOP 快很多。</li></ul><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181435608.png" alt="image-20220618143507520" loading="lazy"></p><h3 id="_5、spring-bean" tabindex="-1"><a class="header-anchor" href="#_5、spring-bean" aria-hidden="true">#</a> 5、Spring Bean</h3><h4 id="_1、什么是-spring-bean" tabindex="-1"><a class="header-anchor" href="#_1、什么是-spring-bean" aria-hidden="true">#</a> 1、什么是 Spring Bean？</h4><p>Bean 代指的就是那些被 IoC 容器所管理的对象</p><p>IoC 容器如何使用配置元数据来管理对象</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181445054.png" alt="image-20220618144512013" loading="lazy"></p><h4 id="_2、将一个类声明为-bean-的注解有哪些" tabindex="-1"><a class="header-anchor" href="#_2、将一个类声明为-bean-的注解有哪些" aria-hidden="true">#</a> 2、将一个类声明为 Bean 的注解有哪些?</h4><ul><li><code>@Component</code> ：通用的注解，可标注任意类为 <code>Spring</code> 组件。如果一个 Bean 不知道属于哪个层，可以使用<code>@Component</code> 注解标注。</li><li><code>@Repository</code> : 对应持久层即 Dao 层，主要用于数据库相关操作。</li><li><code>@Service</code> : 对应服务层，主要涉及一些复杂的逻辑，需要用到 Dao 层。</li><li><code>@Controller</code> : 对应 Spring MVC 控制层，主要用户接受用户请求并调用 Service 层返回数据给前端页面。</li></ul><h4 id="_3、-component-和-bean-的区别是什么" tabindex="-1"><a class="header-anchor" href="#_3、-component-和-bean-的区别是什么" aria-hidden="true">#</a> 3、@Component 和 @Bean 的区别是什么？</h4><p><code>@Component</code> 注解作用于类，而<code>@Bean</code>注解作用于方法。</p><p><code>@Component</code>通常是通过类路径扫描来自动侦测以及自动装配到 Spring 容器中（我们可以使用 <code>@ComponentScan</code> 注解定义要扫描的路径从中找出标识了需要装配的类自动装配到 Spring 的 bean 容器中）。<code>@Bean</code> 注解通常是我们在标有该注解的方法中定义产生这个 bean,<code>@Bean</code>告诉了 Spring 这是某个类的实例，当我需要用它的时候还给我。</p><p><code>@Bean</code> 注解比 <code>@Component</code> 注解的自定义性更强，而且很多地方我们只能通过 <code>@Bean</code> 注解来注册 bean。比如当我们引用第三方库中的类需要装配到 <code>Spring</code>容器时，则只能通过 <code>@Bean</code>来实现。</p><h4 id="_4、注入-bean-的注解有哪些" tabindex="-1"><a class="header-anchor" href="#_4、注入-bean-的注解有哪些" aria-hidden="true">#</a> 4、注入 Bean 的注解有哪些？</h4><p>Spring 内置的 <code>@Autowired</code> 以及 JDK 内置的 <code>@Resource</code> 和 <code>@Inject</code> 都可以用于注入 Bean。</p><table><thead><tr><th>Annotaion</th><th>Package</th><th>Source</th></tr></thead><tbody><tr><td><code>@Autowired</code></td><td><code>org.springframework.bean.factory</code></td><td>Spring 2.5+</td></tr><tr><td><code>@Resource</code></td><td><code>javax.annotation</code></td><td>Java JSR-250</td></tr><tr><td><code>@Inject</code></td><td><code>javax.inject</code></td><td>Java JSR-330</td></tr></tbody></table><p><code>@Autowired</code> 和<code>@Resource</code>使用的比较多一些。</p><h4 id="_5、-autowired-和-resource-的区别是什么" tabindex="-1"><a class="header-anchor" href="#_5、-autowired-和-resource-的区别是什么" aria-hidden="true">#</a> 5、@Autowired 和 @Resource 的区别是什么？</h4><p><strong>总结</strong>：@Autowired注入方式根据类型，不支持根据名称，只有通过@Qualifier来执行名称才可以；@Resource支持类型与名称，默认是根据名称的，提供两个注解值一个是type、一个是name，设置哪个值就选择哪种进行注入。</p><blockquote><p>@Autowired：注入方式为<code>byType</code></p></blockquote><p><code>Autowired</code> 属于 Spring 内置的注解，默认的注入方式为<code>byType</code>（根据类型进行匹配），也就是说会优先根据接口类型去匹配并注入 Bean （接口的实现类</p><ul><li>问题：当一个接口存在多个实现类的话，<code>byType</code>这种方式就无法正确注入对象了，因为这个时候 Spring 会同时找到多个满足条件的选择，默认情况下它自己不知道选择哪一个。</li></ul><p>若是想要用@Autowired来从两个bean中选择一个，可以去配合@Qualifier注解：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 报错，byName 和 byType 都无法匹配到 bean</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">SmsService</span> smsService<span class="token punctuation">;</span>
<span class="token comment">// 正确注入 SmsServiceImpl1 对象对应的 bean</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token keyword">private</span> <span class="token class-name">SmsService</span> smsServiceImpl1<span class="token punctuation">;</span>
<span class="token comment">// 正确注入  SmsServiceImpl1 对象对应的 bean</span>
<span class="token comment">// smsServiceImpl1 就是我们上面所说的名称</span>
<span class="token annotation punctuation">@Autowired</span>
<span class="token annotation punctuation">@Qualifier</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">&quot;smsServiceImpl1&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">SmsService</span> smsService<span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><blockquote><p>@Resource：默认注入方式为 <code>byName</code></p></blockquote><p><code>@Resource</code>属于 JDK 提供的注解，默认注入方式为 <code>byName</code>。如果无法通过名称匹配到对应的 Bean 的话，注入方式会变为<code>byType</code>。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token annotation punctuation">@interface</span> <span class="token class-name">Resource</span> <span class="token punctuation">{</span>
    <span class="token class-name">String</span> <span class="token function">name</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token string">&quot;&quot;</span><span class="token punctuation">;</span>
    <span class="token class-name">Class</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span> <span class="token function">type</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">default</span> <span class="token class-name">Object</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>如果仅指定 <code>name</code> 属性则注入方式为<code>byName</code>，如果仅指定<code>type</code>属性则注入方式为<code>byType</code>，如果同时指定<code>name</code> 和<code>type</code>属性（不建议这么做）则注入方式为<code>byType</code>+<code>byName</code>。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 报错，byName 和 byType 都无法匹配到 bean</span>
<span class="token annotation punctuation">@Resource</span>
<span class="token keyword">private</span> <span class="token class-name">SmsService</span> smsService<span class="token punctuation">;</span>
<span class="token comment">// 正确注入 SmsServiceImpl1 对象对应的 bean</span>
<span class="token annotation punctuation">@Resource</span>
<span class="token keyword">private</span> <span class="token class-name">SmsService</span> smsServiceImpl1<span class="token punctuation">;</span>
<span class="token comment">// 正确注入 SmsServiceImpl1 对象对应的 bean（比较推荐这种方式）</span>
<span class="token annotation punctuation">@Resource</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;smsServiceImpl1&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">private</span> <span class="token class-name">SmsService</span> smsService<span class="token punctuation">;</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_6、bean-的作用域有哪些" tabindex="-1"><a class="header-anchor" href="#_6、bean-的作用域有哪些" aria-hidden="true">#</a> 6、Bean 的作用域有哪些?</h4><p><code>Spring</code> 中 <code>Bean</code> 的作用域通常有下面几种：</p><ul><li><strong>singleton</strong> : 唯一 bean 实例，Spring 中的 bean 默认都是单例的，对单例设计模式的应用。</li><li><strong>prototype</strong> : 每次请求都会创建一个新的 bean 实例。</li><li><strong>request</strong> : 每一次 HTTP 请求都会产生一个新的 bean，该 bean 仅在当前 HTTP request 内有效。</li><li><strong>session</strong> : 每一次来自新 session 的 HTTP 请求都会产生一个新的 bean，该 bean 仅在当前 HTTP session 内有效。</li><li><strong>global-session</strong> ： 全局 session 作用域，仅仅在基于 portlet 的 web 应用中才有意义，Spring5 已经没有了。Portlet 是能够生成语义代码(例如：HTML)片段的小型 Java Web 插件。它们基于 portlet 容器，可以像 servlet 一样处理 HTTP 请求。但是，与 servlet 不同，每个 portlet 都有不同的会话。</li></ul><h4 id="_7、如何配置-bean-的作用域呢" tabindex="-1"><a class="header-anchor" href="#_7、如何配置-bean-的作用域呢" aria-hidden="true">#</a> 7、如何配置 bean 的作用域呢？</h4><p>xml 方式：</p><div class="language-xml ext-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>bean</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>...<span class="token punctuation">&quot;</span></span> <span class="token attr-name">class</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>...<span class="token punctuation">&quot;</span></span> <span class="token attr-name">scope</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>singleton<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>bean</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>注解方式：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Bean</span>
<span class="token annotation punctuation">@Scope</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token class-name">ConfigurableBeanFactory</span><span class="token punctuation">.</span>SCOPE_PROTOTYPE<span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token class-name">Person</span> <span class="token function">personPrototype</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">Person</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><h4 id="_8、单例-bean-的线程安全问题了解吗" tabindex="-1"><a class="header-anchor" href="#_8、单例-bean-的线程安全问题了解吗" aria-hidden="true">#</a> 8、单例 Bean 的线程安全问题了解吗？</h4><p>常见的有两种解决办法：</p><ol><li>在 Bean 中尽量避免定义可变的成员变量。</li><li>在类中定义一个 <code>ThreadLocal</code> 成员变量，将需要的可变成员变量保存在 <code>ThreadLocal</code> 中（推荐的一种方式）。</li></ol><p>不过，大部分 Bean 实际都是无状态（没有实例变量）的（比如 Dao、Service），这种情况下， Bean 是线程安全的。</p><h4 id="_9、bean-的生命周期了解么" tabindex="-1"><a class="header-anchor" href="#_9、bean-的生命周期了解么" aria-hidden="true">#</a> 9、Bean 的生命周期了解么?</h4><p>定义BeanDefinition、实例化前、进行实例化、实例化后、填充属性、初始化前(过程中可进行一个@PostConstrcut执行)、初始化后、AOP</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181615706.png" alt="image-20220618161512608" loading="lazy"></p><ul><li>set注入以及单单属性注入都是属于填充属性阶段；构造器注入是在推断构造方法阶段。</li></ul><blockquote><p>简单定义五步生命周期</p></blockquote><p>若是绑定了初始化以及销毁方法。那么就有五步生命周期</p><p>①无参构造器。</p><p>②set方法执行。</p><p>③init()方法。(初始化方法，需要进行额外配置)</p><p>④获取创建bean实例。</p><p>⑤destory()方法。(销毁方法，需要额外配置)</p><br><blockquote><p>实现一个后置处理器接口</p></blockquote><p>创建一个类并实现一个BeanPostProcessor接口，重写两个方法之后就会默认应用到所有的bean当中去。</p><p>效果就是在初始化init()前后各有一个方法。</p><h3 id="_6、spring的事务" tabindex="-1"><a class="header-anchor" href="#_6、spring的事务" aria-hidden="true">#</a> 6、Spring的事务</h3><h4 id="_1、如何使用事务" tabindex="-1"><a class="header-anchor" href="#_1、如何使用事务" aria-hidden="true">#</a> 1、如何使用事务？</h4><p>具有两种方式：声明式与编程式(没有使用框架前，需要手动beginTransaction()、commit()、rollback())。底层使用的是AOP原理，在Spring中进行声明式。</p><p>首先将DataSourceTransactionManager进行实例化，将数据源datasource交由其进行管理，并且进行实例化。</p><blockquote><p>注解形式</p></blockquote><p>使用<code>@Transactional</code>声明在类或者方法中。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181615366.png" alt="image-20210523153434883" loading="lazy"></p><br><blockquote><p>xml配置</p></blockquote><p>配置事务通知，配置声明及切入点。</p><h4 id="_2、spring-事务中的隔离级别有哪几种" tabindex="-1"><a class="header-anchor" href="#_2、spring-事务中的隔离级别有哪几种" aria-hidden="true">#</a> 2、Spring 事务中的隔离级别有哪几种?</h4><p>下面我依次对每一种事务隔离级别进行介绍：</p><ul><li><strong><code>TransactionDefinition.ISOLATION_DEFAULT</code></strong> :使用后端数据库默认的隔离级别，MySQL 默认采用的 <code>REPEATABLE_READ</code> 隔离级别 Oracle 默认采用的 <code>READ_COMMITTED</code> 隔离级别.</li><li><strong><code>TransactionDefinition.ISOLATION_READ_UNCOMMITTED</code></strong> :最低的隔离级别，使用这个隔离级别很少，因为它允许读取尚未提交的数据变更，<strong>可能会导致脏读、幻读或不可重复读</strong></li><li><strong><code>TransactionDefinition.ISOLATION_READ_COMMITTED</code></strong> : 允许读取并发事务已经提交的数据，<strong>可以阻止脏读，但是幻读或不可重复读仍有可能发生</strong></li><li><strong><code>TransactionDefinition.ISOLATION_REPEATABLE_READ</code></strong> : 对同一字段的多次读取结果都是一致的，除非数据是被本身事务自己所修改，<strong>可以阻止脏读和不可重复读，但幻读仍有可能发生。</strong></li><li><strong><code>TransactionDefinition.ISOLATION_SERIALIZABLE</code></strong> : 最高的隔离级别，完全服从 ACID 的隔离级别。所有的事务依次逐个执行，这样事务之间就完全不可能产生干扰，也就是说，<strong>该级别可以防止脏读、不可重复读以及幻读</strong>。但是这将严重影响程序的性能。通常情况下也不会用到该级别。</li></ul><h4 id="_3、-transactional-rollbackfor-exception-class-注解了解吗" tabindex="-1"><a class="header-anchor" href="#_3、-transactional-rollbackfor-exception-class-注解了解吗" aria-hidden="true">#</a> 3、@Transactional(rollbackFor = Exception.class)注解了解吗？</h4><p><code>Exception</code> 分为运行时异常 <code>RuntimeException</code> 和非运行时异常。事务管理对于企业应用来说是至关重要的，即使出现异常情况，它也可以保证数据的一致性。</p><p>当 <code>@Transactional</code> 注解作用于类上时，该类的所有 public 方法将都具有该类型的事务属性，同时，我们也可以在方法级别使用该标注来覆盖类级别的定义。如果类或者方法加了这个注解，那么这个类里面的方法抛出异常，就会回滚，数据库里面的数据也会回滚。</p><p>在 <code>@Transactional</code> 注解中如果不配置<code>rollbackFor</code>属性,那么事务只会在遇到<code>RuntimeException</code>的时候才会回滚，加上 <code>rollbackFor=Exception.class</code>,可以让事务在遇到非运行时异常时也回滚。</p><p><strong>核心</strong>：默认是RuntimeException也就是运行时异常才会回滚，对于实际业务中一旦出现了非运行时异常就需要进行回滚，所以需要设置Exception.class。</p><hr><h3 id="_7、spring的循环依赖" tabindex="-1"><a class="header-anchor" href="#_7、spring的循环依赖" aria-hidden="true">#</a> 7、Spring的循环依赖</h3><h4 id="_7-1、如何解决循环依赖的问题" tabindex="-1"><a class="header-anchor" href="#_7-1、如何解决循环依赖的问题" aria-hidden="true">#</a> 7.1、如何解决循环依赖的问题？</h4><p>视频：<a href="https://www.bilibili.com/video/BV1ET4y1N7Sp?spm_id_from=333.337.search-card.all.click&amp;vd_source=b19269a4ae00481d5ff13d1897127b8b" target="_blank" rel="noopener noreferrer">第二次讲Spring循环依赖，时长16分钟，我保证每一秒都是精华<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>、<a href="https://www.bilibili.com/video/BV1Ga4y1E7Br?spm_id_from=333.337.search-card.all.click&amp;vd_source=b19269a4ae00481d5ff13d1897127b8b" target="_blank" rel="noopener noreferrer">【子路聊Java】阿里一面：如何满分回答Spring的循环依赖？<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><p>文章：<a href="https://blog.csdn.net/cristianoxm/article/details/113246104" target="_blank" rel="noopener noreferrer">spring循环依赖及解决方法<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>、<a href="https://blog.csdn.net/m0_67393827/article/details/125244657" target="_blank" rel="noopener noreferrer">spring如何解决循环依赖<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>包含循环依赖的N个场景。</p><p>解决springboot2.6开始禁止循环依赖问题：<a href="https://blog.csdn.net/CelineT/article/details/123656675?spm=1001.2101.3001.6650.1&amp;utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-123656675-blog-111590845.pc_relevant_paycolumn_v3&amp;depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-123656675-blog-111590845.pc_relevant_paycolumn_v3&amp;utm_relevant_index=2" target="_blank" rel="noopener noreferrer">The dependencies of some of the beans in the application context form a cycle解决循环依赖<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>、<a href="https://blog.csdn.net/weixin_46044901/article/details/122826554" target="_blank" rel="noopener noreferrer">The dependencies of some of the beans in the application context form a cycle 解决方案<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p><ul><li>springboot2.6开始，默认禁止循环依赖，所以设置yaml配置参数：<code>spring.main.allow-circular-references=true</code></li><li>若是不通过开启循环依赖，我们也可以在对应的@Autowired上设置@Lazy注解。</li></ul><blockquote><p>结论</p></blockquote><p>构造器注入的循环依赖：Spring处理不了，直接抛出 BeanCurrentlylnCreationException 异常。</p><p>单例模式下属性注入的循环依赖：通过三级缓存处理循环依赖。</p><p>非单例循环依赖：无法处理。</p><blockquote><p>分析</p></blockquote><p>下面分析单例模式下属性注入的循环依赖是怎么处理的：</p><p>首先，Spring单例对象的初始化大略分为三步：</p><ol><li>createBeanInstance ：实例化bean，使用构造方法创建对象，为对象分配内存。</li><li>populateBean ：进行依赖注入。</li><li>initializeBean ：初始化bean。</li></ol><p>Spring为了解决单例的循环依赖以及动态代理AOP问题，使用了三级缓存：</p><ul><li>singletonObjects ：完成了初始化的单例对象map，bean name --&gt; bean instance</li><li>earlySingletonObjects ：完成实例化未初始化的单例对象map，bean name --&gt; bean instance</li><li>singletonFactories ： 单例对象工厂map，bean name --&gt; ObjectFactory，单例对象实例化完成之后会加入singletonFactories。</li></ul><p>在调用createBeanInstance进行实例化之后，会调用addSingletonFactory，将单例对象放到singletonFactories中。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">addSingletonFactory</span><span class="token punctuation">(</span><span class="token class-name">String</span> beanName<span class="token punctuation">,</span> <span class="token class-name">ObjectFactory</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token operator">?</span><span class="token punctuation">&gt;</span></span>
                                   singletonFactory<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">notNull</span><span class="token punctuation">(</span>singletonFactory<span class="token punctuation">,</span> <span class="token string">&quot;Singleton factory must not be null&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">synchronized</span> <span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>singletonObjects<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>singletonObjects<span class="token punctuation">.</span><span class="token function">containsKey</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>singletonFactories<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> singletonFactory<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>earlySingletonObjects<span class="token punctuation">.</span><span class="token function">remove</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">this</span><span class="token punctuation">.</span>registeredSingletons<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>假如A依赖了B的实例对象，同时B也依赖A的实例对象。</p><ol><li>A首先完成了实例化，并且将自己添加到singletonFactories中。</li><li>接着进行依赖注入，发现自己依赖对象B，此时就尝试去get(B)。</li><li>发现B还没有被实例化，对B进行实例化。</li><li>然后B在初始化的时候发现自己依赖了对象A，于是尝试get(A)，尝试一级缓存singletonObjects和二级缓存earlySingletonObjects没找到，尝试三级缓存singletonFactories，由于A初始化时将自己添加到了singletonFactories，所以B可以拿到A对象，然后将A从三级缓存中移到二级缓存中。</li><li>B拿到A对象后顺利完成了初始化，然后将自己放入到一级缓存singletonObjects中。</li><li>此时返回A中，A此时能拿到B的对象顺利完成自己的初始化。</li></ol><h4 id="_7-2、为什么解决不了构造函数注入的循环依赖问题" tabindex="-1"><a class="header-anchor" href="#_7-2、为什么解决不了构造函数注入的循环依赖问题" aria-hidden="true">#</a> 7.2、为什么解决不了构造函数注入的循环依赖问题？</h4><p><a href="https://blog.csdn.net/cristianoxm/article/details/113246104" target="_blank" rel="noopener noreferrer">spring循环依赖及解决方法<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>：在四中无法解决的循环依赖问题里面有作讲解。</p><p>在Spring中的流程是：</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>1.调用构造函数，2. 放到三级缓存，3. 属性赋值。其中调用构造函数时会触发所依赖的bean对象的创建。
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>可以看到将对应的beanfactory放入到三级缓存里是在调用构造函数之后的，若是我们在调用构造函数的时候进行注入，此时若是出现循环依赖问题，由于三级缓存中并没有存放的工厂类，那么自然就会出现循环依赖问题！！！</p><h4 id="_7-3、aop的代理对象创建时机" tabindex="-1"><a class="header-anchor" href="#_7-3、aop的代理对象创建时机" aria-hidden="true">#</a> 7.3、AOP的代理对象创建时机？</h4><p><a href="https://blog.csdn.net/gongsenlin341/article/details/111240114" target="_blank" rel="noopener noreferrer">Spring IOC---AOP代理对象生成的时机<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>：仔细描述了代理对象的生成时机。</p><p><a href="https://www.cnblogs.com/jhxxb/p/14098181.html" target="_blank" rel="noopener noreferrer">Spring AOP 代理创建流程与执行流程<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a>：介绍了AOP代理的不同方式。</p><blockquote><p>简述本质</p></blockquote><p><strong>AOP的代理的对象是通过在三级缓存中的对应beanname的beanfactory产生出来的</strong>，这个创建bean的过程里会有创建代理对象的操作，实际上若是某个Bean被代理了，那么这个工厂就是产生出的对应代理类实例，放置到二级缓存中，并且将其进行属性填充到对应的实例里！</p><blockquote><p>详细过程</p></blockquote><p>在实例化到添加属性之间包含一个后置处理器处理，实现了<code>BeanPostProcessor</code>接口的类有这7个，一个一个去执行postProcessAfterInitialization方法。其中<code>AnnotationAwareAspectJAutoProxyCreator</code>就是会实现AOP动态代理，然后返回代理对象。</p><p>在属性注入的过程中，一级缓存和二级缓存中没有找到A对象，而三级缓存singletonFactories当中有A的工厂对象，所以会调用singletonFactory.getObject()来获得A对象。</p><p>这是之前添加工厂对象到singletonFactories的代码，所以其实执行getObject()也就是执行了getEarlyBeanReference方法。</p><p>getEarlyBeanReference的方法代码如下：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token class-name">Object</span> <span class="token function">getEarlyBeanReference</span><span class="token punctuation">(</span><span class="token class-name">String</span> beanName<span class="token punctuation">,</span> <span class="token class-name">RootBeanDefinition</span> mbd<span class="token punctuation">,</span> <span class="token class-name">Object</span> bean<span class="token punctuation">)</span> <span class="token punctuation">{</span>
   <span class="token class-name">Object</span> exposedObject <span class="token operator">=</span> bean<span class="token punctuation">;</span>
   <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mbd<span class="token punctuation">.</span><span class="token function">isSynthetic</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span> <span class="token function">hasInstantiationAwareBeanPostProcessors</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
       <span class="token comment">//遍历的过程中某个bp就有出现AnnotationAwareAspectJAutoProxyCreator</span>
      <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">SmartInstantiationAwareBeanPostProcessor</span> bp <span class="token operator">:</span> <span class="token function">getBeanPostProcessorCache</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span>smartInstantiationAware<span class="token punctuation">)</span> <span class="token punctuation">{</span>
         exposedObject <span class="token operator">=</span> bp<span class="token punctuation">.</span><span class="token function">getEarlyBeanReference</span><span class="token punctuation">(</span>exposedObject<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
      <span class="token punctuation">}</span>
   <span class="token punctuation">}</span>
   <span class="token keyword">return</span> exposedObject<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271113065.png" alt="image-20220627111352985" loading="lazy"></p><p>基于类型和名字 创建缓存key，将其放入到earlyProxyReferences集合当中，用于<strong>表示进行了提前的动态代理</strong>。调用wrapIfNecessary来构建动态代理对象。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code>ublic <span class="token class-name">Object</span> <span class="token function">getEarlyBeanReference</span><span class="token punctuation">(</span><span class="token class-name">Object</span> bean<span class="token punctuation">,</span> <span class="token class-name">String</span> beanName<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Object</span> cacheKey <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getCacheKey</span><span class="token punctuation">(</span>bean<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>earlyProxyReferences<span class="token punctuation">.</span><span class="token function">put</span><span class="token punctuation">(</span>cacheKey<span class="token punctuation">,</span> bean<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">wrapIfNecessary</span><span class="token punctuation">(</span>bean<span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> cacheKey<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>此时获得到了被代理后的A对象，三个集合的结果如下：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271114540.png" alt="image-20220627111448473" loading="lazy"></p><p>之后doCreateBean 构建B的过程结束了，获得了B对象。</p><p>之后会将这个对象，添加到singletonObjects集合当中，三个集合的结果如下：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271115304.png" alt="image-20220627111516236" loading="lazy"></p><p>B对象构建完成了，那么此时A就可以完成它的填充了，所以走完剩下的逻辑之后，三个集合的结果如下：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206271115803.png" alt="image-20220627111530742" loading="lazy"></p><p>综上提前动态代理，其实是在依赖注入的时候，也就是在populateBean属性填充方法内完成的。</p><h4 id="_7-4、为什么-lazy可以解决循环依赖问题" tabindex="-1"><a class="header-anchor" href="#_7-4、为什么-lazy可以解决循环依赖问题" aria-hidden="true">#</a> 7.4、为什么@Lazy可以解决循环依赖问题</h4><blockquote><p><a href="https://blog.csdn.net/m0_54850604/article/details/123812336" target="_blank" rel="noopener noreferrer">Spring中的 @Lazy注解简析<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>想要 Spring 在启动的时候延迟加载 bean，即在调用某个 bean 的时候再去初始化，那么就可以使用 @Lazy 注解。</p><h2 id="springmvc" tabindex="-1"><a class="header-anchor" href="#springmvc" aria-hidden="true">#</a> SpringMVC</h2><p>核心：<code>DisaptcherServlet</code>。</p><h3 id="_1、简述springmvc的工作原理" tabindex="-1"><a class="header-anchor" href="#_1、简述springmvc的工作原理" aria-hidden="true">#</a> 1、简述SpringMVC的工作原理</h3><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181627980.png" alt="image-20220618162749914" loading="lazy"></p><p><strong>流程说明（重要）：</strong></p><ol><li>客户端（浏览器）发送请求，直接请求到 <code>DispatcherServlet</code>。</li><li><code>DispatcherServlet</code> 根据请求信息调用 <code>HandlerMapping</code>，解析请求对应的 <code>Handler</code>。</li><li>解析到对应的 <code>Handler</code>（也就是我们平常说的 <code>Controller</code> 控制器）后，开始由 <code>HandlerAdapter</code> 适配器处理。</li><li><code>HandlerAdapter</code> 会根据 <code>Handler</code>来调用真正的处理器开处理请求，并处理相应的业务逻辑。</li><li>处理器处理完业务后，会返回一个 <code>ModelAndView</code> 对象，<code>Model</code> 是返回的数据对象，<code>View</code> 是个逻辑上的 <code>View</code>。</li><li><code>ViewResolver</code> 会根据逻辑 <code>View</code> 查找实际的 <code>View</code>。</li><li><code>DispaterServlet</code> 把返回的 <code>Model</code> 传给 <code>View</code>（视图渲染）。</li><li>把 <code>View</code> 返回给请求者（浏览器）</li></ol><br><hr><h3 id="_2、springmvc的常用注解" tabindex="-1"><a class="header-anchor" href="#_2、springmvc的常用注解" aria-hidden="true">#</a> 2、SpringMVC的常用注解</h3><p>@RequestMapping：对应所有请求的路径地址。</p><p>@RestController：其中包含了@ResponseBody。结合@Controller和@ResponseBody。</p><p>@GetMapping、@PostMapping、@PutMapping。</p><p>@PathVariable：获取注解中请求地址的{}里的内容。</p><p>@RequestParam：使用一个别名来进行接收。</p><p>@RequestBody：获取请求体。</p><p>@CookieValue(value = &quot;JSESSIONID&quot;)：获取到指定的cookie。</p><p>@SessionAttribute ：获取到指定的session。</p><p>@ResponseBody：注解实现将 controller 方法返回对象转化为 json 响应给客户。</p><br><hr><h3 id="_3、异常处理" tabindex="-1"><a class="header-anchor" href="#_3、异常处理" aria-hidden="true">#</a> 3、异常处理</h3><p>实现HandlerExceptionResolver接口，并且注入到IOC容器中。</p><p>自定义异常。</p><blockquote><p>全局异常捕捉器</p></blockquote><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>@RestControllerAdvice  //注解
//接着在方法上添加@ExceptionHandler来指定捕捉权限校验异常
/**
* 权限校验异常
*/
@ExceptionHandler
@ExceptionHandler(AccessDeniedException.class)
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><br><hr><h3 id="_4、拦截器" tabindex="-1"><a class="header-anchor" href="#_4、拦截器" aria-hidden="true">#</a> 4、拦截器</h3><p>实现<code>HandlerInterceptor</code>接口，并且交由<code>IOC</code>容器管理，包含三个方法：</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181620414.png" alt="image-20210523161956065" loading="lazy"></p><h3 id="_5、说说自己对于-spring-mvc-了解" tabindex="-1"><a class="header-anchor" href="#_5、说说自己对于-spring-mvc-了解" aria-hidden="true">#</a> 5、说说自己对于 Spring MVC 了解?</h3><p>MVC 是模型(Model)、视图(View)、控制器(Controller)的简写，其核心思想是通过将业务逻辑、数据、显示分离来组织代码。</p><p>想要真正理解 Spring MVC，我们先来看看 Model 1 和 Model 2 这两个没有 Spring MVC 的时代。</p><blockquote><p>Model 1时代</p></blockquote><p>这个模式下 JSP 即是控制层（Controller）又是表现层（View）。显而易见，这种模式存在很多问题。比如控制逻辑和表现逻辑混杂在一起，导致代码重用率极低；再比如前端和后端相互依赖，难以进行测试维护并且开发效率极低。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181624906.png" alt="image-20220618162447798" loading="lazy"></p><blockquote><p>Model 2时代</p></blockquote><p>学过 Servlet 并做过相关 Demo 的朋友应该了解“Java Bean(Model)+ JSP（View）+Servlet（Controller） ”这种开发模式，这就是早期的 JavaWeb MVC 开发模式。</p><ul><li>Model:系统涉及的数据，也就是 dao 和 bean。</li><li>View：展示模型中的数据，只是用来展示。</li><li>Controller：处理用户请求都发送给 ，返回数据给 JSP 并展示给用户。</li></ul><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206181625704.png" alt="image-20220618162517614" loading="lazy"></p><p>Model2 模式下还存在很多问题，Model2 的抽象和封装程度还远远不够，使用 Model2 进行开发时不可避免地会重复造轮子，这就大大降低了程序的可维护性和复用性。</p><p>于是，很多 JavaWeb 开发相关的 MVC 框架应运而生比如 Struts2，但是 Struts2 比较笨重。</p><blockquote><p>Spring MVC 时代</p></blockquote><p>随着 Spring 轻量级开发框架的流行，Spring 生态圈出现了 Spring MVC 框架， Spring MVC 是当前最优秀的 MVC 框架。相比于 Struts2 ， Spring MVC 使用更加简单和方便，开发效率更高，并且 Spring MVC 运行速度更快。</p><p><strong>总结</strong>：MVC 是一种设计模式，Spring MVC 是一款很优秀的 MVC 框架。Spring MVC 可以帮助我们进行更简洁的 Web 层的开发，并且它天生与 Spring 框架集成。Spring MVC 下我们一般把后端项目分为 Service 层（处理业务）、Dao 层（数据库操作）、Entity 层（实体类）、Controller 层(控制层，返回数据给前台页面)。</p><hr><h2 id="mybatis" tabindex="-1"><a class="header-anchor" href="#mybatis" aria-hidden="true">#</a> Mybatis</h2><p>ORM映射框架。</p><h3 id="使用到的设计模式" tabindex="-1"><a class="header-anchor" href="#使用到的设计模式" aria-hidden="true">#</a> 使用到的设计模式</h3><p>建造者模式、工厂模式、代理模式。</p><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206182004690.png" alt="image-20210523165131038" loading="lazy"></p><br><hr><h3 id="_1、mybatis-中-和-的区别" tabindex="-1"><a class="header-anchor" href="#_1、mybatis-中-和-的区别" aria-hidden="true">#</a> 1、Mybatis 中#和$的区别</h3><blockquote><h1 id="" tabindex="-1"><a class="header-anchor" href="#" aria-hidden="true">#</a></h1></blockquote><p><code>#{}</code>：会进行预编译，而且进行类型匹配。变量的传递必须使用#{}，使用#{}就相当于<code>PrepareStatement</code>这种占位符的形式，提高效率，可以放置SQL注入问题。</p><p><strong>应用场景</strong>：一般用于传入添加，修改的值或查询，删除的where条件 id值。</p><br><blockquote><p>$</p></blockquote><p><code>$</code>：不进行数据类型匹配，实质上是字符串拼接，就是把<code>${}</code>替换成变量的值，调用Statement来赋值，具有SQL注入的问题</p><p><strong>应用场景</strong>：方式一般用于传入数据库对象，比如这种group by 字段 ,order by 字段，表名，字段名等没法使用占位符的就需要使用${}。</p><br><blockquote><p>SQL注入场景</p></blockquote><p>例如：select * from user where username=? and password = ?</p><p>第一个参数传&quot;，第二个参数传&quot; or &#39;1&#39; = &#39;1&#39;。</p><p>若是使用${}，字符串拼接的话就会形成：<code>select * from user where username= “ and password = ” or &#39;1&#39;=&#39;1&#39;;</code>该条语句是百分百成立的，这就是SQL注入。</p><p><strong>解决方案</strong>：通过参数SQL预编译的方案来进行解决SQL注入，预编译处理sql时，对应的参数值中有山城歧义的就会进行处理，只会被当成一个参数！</p><p><strong>总结</strong>：总而言之就是#{}没有sql注入的问题存在(SQL注入就是将原本的SQL语句的逻辑结构改变，使得SQL语句的执行结果和原本开发者的意图不一样)，使用预编译语句执行者就可以避免这个问题，prepareStatement将sql预编译，传参数的时候，不会改变sql语句结构，就可以避免注入。预编译的解释如下：</p><ul><li><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206182004562.png" alt="image-20210523164040903" loading="lazy"></li></ul><br><hr><h3 id="_2、mybatis的编程步骤" tabindex="-1"><a class="header-anchor" href="#_2、mybatis的编程步骤" aria-hidden="true">#</a> 2、Mybatis的编程步骤？</h3><p>1、创建 SqlSessionFactory。(通过SqlSessionFactoryBuilder调用build()读取配置文件后获取)。</p><p>2、通过 SqlSessionFactory 创建 SqlSession。(调用SqlSessionFactory的openSession，产生一个会话。)</p><p>3、通过sqlsession 执行数据库操作。(使用getMapper传入dao接口获取其代理对象，接着调用方法来执行sql语句)</p><p>4、调用session.commit()提交事务。</p><p>5、调用session.close()关闭会话。</p><br><hr><h3 id="_3、一级缓存与二级缓存" tabindex="-1"><a class="header-anchor" href="#_3、一级缓存与二级缓存" aria-hidden="true">#</a> 3、一级缓存与二级缓存</h3><p>一级缓存与二级缓存都使用的HashMap来进行。</p><blockquote><p>一级缓存</p></blockquote><p>一级指的是<code>Mybatis</code>中<code>SqlSession</code>对象的缓存。</p><p>第一次执行查询后，查询结果会同时存入到SqlSession中的一块区域。第二次查询时会先去sqlSession中查看是否有，没有的话再去数据库查。</p><p><strong>开启条件</strong>：不需要进行手动设置，就会有一级缓存。</p><p><strong>触发清空一级缓存情况</strong>：当调用 SqlSession 的修改，添加，删除，commit()，close()等，方法时，就会清空一级缓存。</p><br><blockquote><p>二级缓存</p></blockquote><p><img src="https://pictured-bed.oss-cn-beijing.aliyuncs.com/img/2022/6/202206182004637.png" alt="image-20210523170005584" loading="lazy"></p><h3 id="_4、xml-映射文件中-除了常见的-select-insert-update-delete-标签之外-还有哪些标签" tabindex="-1"><a class="header-anchor" href="#_4、xml-映射文件中-除了常见的-select-insert-update-delete-标签之外-还有哪些标签" aria-hidden="true">#</a> 4、Xml 映射文件中，除了常见的 select|insert|update|delete 标签之外，还有哪些标签？</h3><p>还有很多其他的标签， <code>&lt;resultMap&gt;</code> 、 <code>&lt;parameterMap&gt;</code> 、 <code>&lt;sql&gt;</code> 、 <code>&lt;include&gt;</code> 、 <code>&lt;selectKey&gt;</code> ，加上动态 sql 的 9 个标签， <code>trim|where|set|foreach|if|choose|when|otherwise|bind</code> 等，其中 <code>&lt;sql&gt;</code> 为 sql 片段标签，通过 <code>&lt;include&gt;</code> 标签引入 sql 片段， <code>&lt;selectKey&gt;</code> 为不支持自增的主键生成策略标签。</p><h3 id="_5、最佳实践中-通常一个-xml-映射文件-都会写一个-dao-接口与之对应-请问-这个-dao-接口的工作原理是什么-dao-接口里的方法-参数不同时-方法能重载吗" tabindex="-1"><a class="header-anchor" href="#_5、最佳实践中-通常一个-xml-映射文件-都会写一个-dao-接口与之对应-请问-这个-dao-接口的工作原理是什么-dao-接口里的方法-参数不同时-方法能重载吗" aria-hidden="true">#</a> 5、最佳实践中，通常一个 Xml 映射文件，都会写一个 Dao 接口与之对应，请问，这个 Dao 接口的工作原理是什么？Dao 接口里的方法，参数不同时，方法能重载吗？</h3><p>答：Dao 接口，就是人们常说的 <code>Mapper</code> 接口，接口的全限名，就是映射文件中的 namespace 的值，接口的方法名，就是映射文件中 <code>MappedStatement</code> 的 id 值，接口方法内的参数，就是传递给 sql 的参数。 <code>Mapper</code> 接口是没有实现类的，当调用接口方法时，接口全限名+方法名拼接字符串作为 key 值，可唯一定位一个 <code>MappedStatement</code> ，举例： <code>com.mybatis3.mappers. StudentDao.findStudentById</code> ，可以唯一找到 namespace 为 <code>com.mybatis3.mappers. StudentDao</code> 下面 <code>id = findStudentById</code> 的 <code>MappedStatement</code> 。在 MyBatis 中，每一个 <code>&lt;select&gt;</code> 、 <code>&lt;insert&gt;</code> 、 <code>&lt;update&gt;</code> 、 <code>&lt;delete&gt;</code> 标签，都会被解析为一个 <code>MappedStatement</code> 对象。</p><p><strong>Mybatis 的 Dao 接口可以有多个重载方法，但是多个接口对应的映射必须只有一个，否则启动会报错。</strong></p><p>Dao 接口的工作原理是 JDK 动态代理，MyBatis 运行时会使用 JDK 动态代理为 Dao 接口生成代理 proxy 对象，代理对象 proxy 会拦截接口方法，转而执行 <code>MappedStatement</code> 所代表的 sql，然后将 sql 执行结果返回。</p><p>Dao 接口方法可以重载，但是需要满足以下条件：</p><ol><li>仅有一个无参方法和一个有参方法</li><li>多个有参方法时，参数数量必须一致。且使用相同的 <code>@Param</code> ，或者使用 <code>param1</code> 这种</li></ol><h3 id="_6、mybatis-是如何进行分页的-分页插件的原理是什么" tabindex="-1"><a class="header-anchor" href="#_6、mybatis-是如何进行分页的-分页插件的原理是什么" aria-hidden="true">#</a> 6、MyBatis 是如何进行分页的？分页插件的原理是什么？</h3><p><strong>(1)</strong> MyBatis 使用 RowBounds 对象进行分页，它是针对 ResultSet 结果集执行的内存分页，而非物理分页；<strong>(2)</strong> 可以在 sql 内直接书写带有物理分页的参数来完成物理分页功能，<strong>(3)</strong> 也可以使用分页插件来完成物理分页。</p><p>分页插件的基本原理是使用 MyBatis 提供的插件接口，实现自定义插件，在插件的拦截方法内拦截待执行的 sql，然后重写 sql，根据 dialect 方言，添加对应的物理分页语句和物理分页参数。</p><p>举例： <code>select _ from student</code> ，拦截 sql 后重写为： <code>select t._ from （select \* from student）t limit 0，10</code></p><h3 id="_7、简述-mybatis-的插件运行原理-以及如何编写一个插件。" tabindex="-1"><a class="header-anchor" href="#_7、简述-mybatis-的插件运行原理-以及如何编写一个插件。" aria-hidden="true">#</a> 7、简述 MyBatis 的插件运行原理，以及如何编写一个插件。</h3><p>MyBatis 仅可以编写针对 <code>ParameterHandler</code> 、 <code>ResultSetHandler</code> 、 <code>StatementHandler</code> 、 <code>Executor</code> 这 4 种接口的插件，</p><p>MyBatis 使用 JDK 的动态代理，为需要拦截的接口生成代理对象以实现接口方法拦截功能，每当执行这 4 种接口对象的方法时，就会进入拦截方法，具体就是 <code>InvocationHandler</code> 的 <code>invoke()</code> 方法，当然，只会拦截那些你指定需要拦截的方法。</p><p>实现 MyBatis 的 Interceptor 接口并复写 <code>intercept()</code> 方法，然后在给插件编写注解，指定要拦截哪一个接口的哪些方法即可，记住，别忘了在配置文件中配置你编写的插件。</p><h3 id="_8、mybatis-执行批量插入-能返回数据库主键列表吗" tabindex="-1"><a class="header-anchor" href="#_8、mybatis-执行批量插入-能返回数据库主键列表吗" aria-hidden="true">#</a> 8、MyBatis 执行批量插入，能返回数据库主键列表吗？</h3><p>能，JDBC 都能，MyBatis 当然也能。</p><h3 id="_9、mybatis-动态-sql-是做什么的-都有哪些动态-sql-能简述一下动态-sql-的执行原理不" tabindex="-1"><a class="header-anchor" href="#_9、mybatis-动态-sql-是做什么的-都有哪些动态-sql-能简述一下动态-sql-的执行原理不" aria-hidden="true">#</a> 9、MyBatis 动态 sql 是做什么的？都有哪些动态 sql？能简述一下动态 sql 的执行原理不？</h3><p>MyBatis 动态 sql 可以让我们在 Xml 映射文件内，以标签的形式编写动态 sql，完成逻辑判断和动态拼接 sql 的功能，MyBatis 提供了 9 种动态 sql 标签 <code>trim|where|set|foreach|if|choose|when|otherwise|bind</code> 。</p><p>其执行原理为，<strong>使用 OGNL 从 sql 参数对象中计算表达式的值，根据表达式的值动态拼接 sql，以此来完成动态 sql 的功能</strong>。</p><h3 id="_10、mybatis-是如何将-sql-执行结果封装为目标对象并返回的-都有哪些映射形式" tabindex="-1"><a class="header-anchor" href="#_10、mybatis-是如何将-sql-执行结果封装为目标对象并返回的-都有哪些映射形式" aria-hidden="true">#</a> 10、MyBatis 是如何将 sql 执行结果封装为目标对象并返回的？都有哪些映射形式？</h3><p>第一种是使用 <code>&lt;resultMap&gt;</code> 标签，逐一定义列名和对象属性名之间的映射关系。第二种是使用 sql 列的别名功能，将列别名书写为对象属性名，比如 T_NAME AS NAME，对象属性名一般是 name，小写，但是列名不区分大小写，MyBatis 会忽略列名大小写，智能找到与之对应对象属性名，你甚至可以写成 T_NAME AS NaMe，MyBatis 一样可以正常工作。</p><p>有了列名与属性名的映射关系后，MyBatis 通过反射创建对象，同时使用反射给对象的属性逐一赋值并返回，那些找不到映射关系的属性，是无法完成赋值的。</p><h3 id="_11、mybatis-能执行一对一、一对多的关联查询吗-都有哪些实现方式-以及它们之间的区别。" tabindex="-1"><a class="header-anchor" href="#_11、mybatis-能执行一对一、一对多的关联查询吗-都有哪些实现方式-以及它们之间的区别。" aria-hidden="true">#</a> 11、MyBatis 能执行一对一、一对多的关联查询吗？都有哪些实现方式，以及它们之间的区别。</h3><p>关联对象查询，有两种实现方式，一种是单独发送一个 sql 去查询关联对象，赋给主对象，然后返回主对象。另一种是使用嵌套查询，嵌套查询的含义为使用 join 查询，一部分列是 A 对象的属性值，另外一部分列是关联对象 B 的属性值，好处是只发一个 sql 查询，就可以把主对象和其关联对象查出来。</p><p>那么问题来了，join 查询出来 100 条记录，如何确定主对象是 5 个，而不是 100 个？其去重复的原理是 <code>&lt;resultMap&gt;</code> 标签内的 <code>&lt;id&gt;</code> 子标签，指定了唯一确定一条记录的 id 列，MyBatis 根据 <code>&lt;id&gt;</code> 列值来完成 100 条记录的去重复功能， <code>&lt;id&gt;</code> 可以有多个，代表了联合主键的语意。</p><p>同样主对象的关联对象，也是根据这个原理去重复的，尽管一般情况下，只有主对象会有重复记录，关联对象一般不会重复。</p><h3 id="_12、mybatis-是否支持延迟加载-如果支持-它的实现原理是什么" tabindex="-1"><a class="header-anchor" href="#_12、mybatis-是否支持延迟加载-如果支持-它的实现原理是什么" aria-hidden="true">#</a> 12、MyBatis 是否支持延迟加载？如果支持，它的实现原理是什么？</h3><p>MyBatis 仅支持 association 关联对象和 collection 关联集合对象的延迟加载，association 指的就是一对一，collection 指的就是一对多查询。在 MyBatis 配置文件中，可以配置是否启用延迟加载 <code>lazyLoadingEnabled=true|false。</code></p><p>它的原理是，使用 <code>CGLIB</code> 创建目标对象的代理对象，当调用目标方法时，进入拦截器方法，比如调用 <code>a.getB().getName()</code> ，拦截器 <code>invoke()</code> 方法发现 <code>a.getB()</code> 是 null 值，那么就会单独发送事先保存好的查询关联 B 对象的 sql，把 B 查询上来，然后调用 a.setB(b)，于是 a 的对象 b 属性就有值了，接着完成 <code>a.getB().getName()</code> 方法的调用。这就是延迟加载的基本原理。</p><p>当然了，不光是 MyBatis，几乎所有的包括 Hibernate，支持延迟加载的原理都是一样的。</p><h3 id="_13、mybatis-的-xml-映射文件中-不同的-xml-映射文件-id-是否可以重复" tabindex="-1"><a class="header-anchor" href="#_13、mybatis-的-xml-映射文件中-不同的-xml-映射文件-id-是否可以重复" aria-hidden="true">#</a> 13、MyBatis 的 Xml 映射文件中，不同的 Xml 映射文件，id 是否可以重复？</h3><p>不同的 Xml 映射文件，如果配置了 namespace，那么 id 可以重复；如果没有配置 namespace，那么 id 不能重复；毕竟 namespace 不是必须的，只是最佳实践而已。</p><p>原因就是 namespace+id 是作为 <code>Map&lt;String, MappedStatement&gt;</code> 的 key 使用的，如果没有 namespace，就剩下 id，那么，id 重复会导致数据互相覆盖。有了 namespace，自然 id 就可以重复，namespace 不同，namespace+id 自然也就不同。</p><h3 id="_14、mybatis-中如何执行批处理" tabindex="-1"><a class="header-anchor" href="#_14、mybatis-中如何执行批处理" aria-hidden="true">#</a> 14、MyBatis 中如何执行批处理？</h3><p>使用 BatchExecutor 完成批处理。</p><p>MyBatis 有三种基本的 Executor 执行器，** <code>SimpleExecutor</code> 、 <code>ReuseExecutor</code> 、 <code>BatchExecutor</code> 。**</p><p>** <code>SimpleExecutor</code> ：**每执行一次 update 或 select，就开启一个 Statement 对象，用完立刻关闭 Statement 对象。</p><p>** <code>ReuseExecutor</code> ：**执行 update 或 select，以 sql 作为 key 查找 Statement 对象，存在就使用，不存在就创建，用完后，不关闭 Statement 对象，而是放置于 Map&lt;String, Statement&gt;内，供下一次使用。简言之，就是重复使用 Statement 对象。</p><p>** <code>BatchExecutor</code> ：**执行 update（没有 select，JDBC 批处理不支持 select），将所有 sql 都添加到批处理中（addBatch()），等待统一执行（executeBatch()），它缓存了多个 Statement 对象，每个 Statement 对象都是 addBatch()完毕后，等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。</p><p>作用范围：Executor 的这些特点，都严格限制在 SqlSession 生命周期范围内。</p><h3 id="_15、mybatis-中如何指定使用哪一种-executor-执行器" tabindex="-1"><a class="header-anchor" href="#_15、mybatis-中如何指定使用哪一种-executor-执行器" aria-hidden="true">#</a> 15、MyBatis 中如何指定使用哪一种 Executor 执行器？</h3><p>在 MyBatis 配置文件中，可以指定默认的 ExecutorType 执行器类型，也可以手动给 <code>DefaultSqlSessionFactory</code> 的创建 SqlSession 的方法传递 ExecutorType 类型参数。</p><h3 id="_16、mybatis-是否可以映射-enum-枚举类" tabindex="-1"><a class="header-anchor" href="#_16、mybatis-是否可以映射-enum-枚举类" aria-hidden="true">#</a> 16、MyBatis 是否可以映射 Enum 枚举类？</h3><p>MyBatis 可以映射枚举类，不单可以映射枚举类，MyBatis 可以映射任何对象到表的一列上。映射方式为自定义一个 <code>TypeHandler</code> ，实现 <code>TypeHandler</code> 的 <code>setParameter()</code> 和 <code>getResult()</code> 接口方法。 <code>TypeHandler</code> 有两个作用，一是完成从 javaType 至 jdbcType 的转换，二是完成 jdbcType 至 javaType 的转换，体现为 <code>setParameter()</code> 和 <code>getResult()</code> 两个方法，分别代表设置 sql 问号占位符参数和获取列查询结果。</p><h3 id="_17、mybatis-映射文件中-如果-a-标签通过-include-引用了-b-标签的内容-请问-b-标签能否定义在-a-标签的后面-还是说必须定义在-a-标签的前面" tabindex="-1"><a class="header-anchor" href="#_17、mybatis-映射文件中-如果-a-标签通过-include-引用了-b-标签的内容-请问-b-标签能否定义在-a-标签的后面-还是说必须定义在-a-标签的前面" aria-hidden="true">#</a> 17、MyBatis 映射文件中，如果 A 标签通过 include 引用了 B 标签的内容，请问，B 标签能否定义在 A 标签的后面，还是说必须定义在 A 标签的前面？</h3><p>虽然 MyBatis 解析 Xml 映射文件是按照顺序解析的，但是，<strong>被引用的 B 标签依然可以定义在任何地方，MyBatis 都可以正确识别</strong>。</p><p>原理是，MyBatis 解析 A 标签，发现 A 标签引用了 B 标签，但是 B 标签尚未解析到，尚不存在，此时，MyBatis 会将 A 标签标记为未解析状态，然后继续解析余下的标签，包含 B 标签，待所有标签解析完毕，MyBatis 会重新解析那些被标记为未解析的标签，此时再解析 A 标签时，B 标签已经存在，A 标签也就可以正常解析完成了。</p><h3 id="_18、简述-mybatis-的-xml-映射文件和-mybatis-内部数据结构之间的映射关系" tabindex="-1"><a class="header-anchor" href="#_18、简述-mybatis-的-xml-映射文件和-mybatis-内部数据结构之间的映射关系" aria-hidden="true">#</a> 18、简述 MyBatis 的 Xml 映射文件和 MyBatis 内部数据结构之间的映射关系？</h3><p>MyBatis 将所有 Xml 配置信息都封装到 All-In-One 重量级对象 Configuration 内部。在 Xml 映射文件中， <code>&lt;parameterMap&gt;</code> 标签会被解析为 <code>ParameterMap</code> 对象，其每个子元素会被解析为 ParameterMapping 对象。 <code>&lt;resultMap&gt;</code> 标签会被解析为 <code>ResultMap</code> 对象，其每个子元素会被解析为 <code>ResultMapping</code> 对象。每一个 <code>&lt;select&gt;、&lt;insert&gt;、&lt;update&gt;、&lt;delete&gt;</code> 标签均会被解析为 <code>MappedStatement</code> 对象，标签内的 sql 会被解析为 BoundSql 对象。</p><h3 id="_19、为什么说-mybatis-是半自动-orm-映射工具-它与全自动的区别在哪里" tabindex="-1"><a class="header-anchor" href="#_19、为什么说-mybatis-是半自动-orm-映射工具-它与全自动的区别在哪里" aria-hidden="true">#</a> 19、为什么说 MyBatis 是半自动 ORM 映射工具？它与全自动的区别在哪里？</h3><p>Hibernate 属于全自动 ORM 映射工具，使用 Hibernate 查询关联对象或者关联集合对象时，<strong>可以根据对象关系模型直接获取</strong>，所以它是全自动的。而 MyBatis 在查询关联对象或关联集合对象时，需要手动编写 sql 来完成，所以，称之为半自动 ORM 映射工具。</p><br><h2 id="springboot" tabindex="-1"><a class="header-anchor" href="#springboot" aria-hidden="true">#</a> SpringBoot</h2><h3 id="_1、自动装配原理-自定义starter" tabindex="-1"><a class="header-anchor" href="#_1、自动装配原理-自定义starter" aria-hidden="true">#</a> 1、自动装配原理（自定义starter）</h3><blockquote><p><a href="https://www.cnblogs.com/cxxxxxx/p/13417469.html" target="_blank" rel="noopener noreferrer">SpringBoot自动装配原理详解面试<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span></a></p></blockquote><p>启动类注解作用：</p><ul><li>在<code>@SpringBootApplication</code>注解中有一个<code>@EnableAutoConfiguration</code>其中有一个<code>@Import(AutoConfigurationImportSelector.class)</code>相当于导入了一个组件。通过beanpostprocessor后置处理器来执行其中的<code>selectImports()</code>方法会读取<code>spring.factories</code>配置文件，其中包含了所有springboot的自动配置类(<code>xxxAutoConfiguration</code>)，对应配置类中对应绑定了<code>Properties</code>结尾命名的类(该类中包含了对应模块的属性，若是springboot配置文件中配置了相关项就会使用，若是没有就会使用默认配置值。)。只会加载生效对应starter的jar包。</li></ul><p>run()方法作用：</p><ul><li><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>1、推断应用的类型是普通的项目还是Web项目

2、查找并加载所有可用初始化器 ， 设置到initializers属性中

3、找出所有的应用程序监听器，设置到listeners属性中

4、推断并设置main方法的定义类，找到运行的主类
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div></li></ul><p><strong>SpringBoot不需要写配置文件的原因</strong>：SpringBoot所有配置都是在启动的时候进行扫描并加载，SpringBoot的所有自动配置类都在Spring.factories里面，但是不一定会生效，生效前要判断条件是否成立，只要导入了对应的start，就有对应的启动器，有了启动器就能帮我们进行自动配置类。</p><blockquote><p>核心总结</p></blockquote><p>SpringBoot自动配置原理，我的理解是这样的：</p><p>1、引入Starter组件</p><p>2、SpringBoot基于约定去Starter组件的路径下（META-INF/spring.factories）去找配置类</p><p>3、SpringBoot使用ImportSelector去导入这些配置类，并根据@Conditional动态加载配置类里面的Bean到容器.</p><p><strong>到这里可能面试官会问你:“<code>spring.factories</code>中这么多配置，每次启动都要全部加载么</strong>？</p><ul><li>只有通过<code>@ConditionalOnXXX</code> 中的所有条件都满足了以后才会进行加载。</li></ul><br><hr><h3 id="_2、spring、springmvc、springboot区别" tabindex="-1"><a class="header-anchor" href="#_2、spring、springmvc、springboot区别" aria-hidden="true">#</a> 2、spring、springmvc、springboot区别</h3><p><code>Spring</code>是一个IOC容器，用于管理Bean，通过DI依赖注入的方式实现控制反转，可以方便的整合各种框架，且提供了AOP机制弥补了OOP的代码重复问题，更方便的将不同类不同方法中的共同处理抽取成为切面，自动注入给方法执行，例如异常、日志</p><p><code>SpringMVC</code>是spring对web框架的一个解决方案，提供了一个总的前端控制器servlet，用于接受请求，然后定义了一套路由策略（url到heandler的映射）以及适配执行handler，将handler处理的结果使用视图解析器生成视图展现给前端</p><p><code>SpringBoot</code>是spring提供的一个快速开发工具包，让程序员能更方便、快速的开发spring+springmvc的应用，约定大于配置，通过stater机制整合了一系列的解决方案，使得redis、mongodb、es可以开箱即用</p><br></div><!----><footer class="page-meta"><div class="meta-item edit-link"><a href="https://gitee.com/changluJava/personal-reading/edit/main/demo/src/zh/interview/主流框架.md" rel="noopener noreferrer" target="_blank" aria-label="编辑此页" class="nav-link label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon edit-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="edit icon"><path d="M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"></path><path d="M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"></path></svg><!--]-->编辑此页<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><!----><!----></footer><nav class="page-nav"><a href="/zh/interview/Redis.html" class="nav-link prev" aria-label="Redis"><div class="hint"><span class="arrow left"></span>上一页</div><div class="link"><span class="icon iconfont icon-lock" style=""></span>Redis</div></a><a href="/zh/interview/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%8E%E9%AB%98%E6%80%A7%E8%83%BD%E9%AB%98%E5%8F%AF%E7%94%A8.html" class="nav-link next" aria-label="分布式"><div class="hint">下一页<span class="arrow right"></span></div><div class="link">分布式<span class="icon iconfont icon-lock" style=""></span></div></a></nav><div class="giscus-wrapper input-top" style="display:block;"><div style="text-align:center">Loading...</div></div><!----><!--]--></main><!--]--><footer class="footer-wrapper"><div class="footer">默认页脚</div><div class="copyright">Copyright © 2022 长路</div></footer><!--]--></div><!--]--><!----><!--]--></div>
    <script type="module" src="/assets/app.e732cc94.js" defer></script>
  </body>
</html>
